diff --git a/netbox/circuits/filtersets.py b/netbox/circuits/filtersets.py index cf250584f..8e4c9ab06 100644 --- a/netbox/circuits/filtersets.py +++ b/netbox/circuits/filtersets.py @@ -1,5 +1,6 @@ import django_filters from django.db.models import Q +from django.utils.translation import gettext as _ from dcim.filtersets import CabledObjectFilterSet from dcim.models import Region, Site, SiteGroup @@ -24,43 +25,43 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): queryset=Region.objects.all(), field_name='circuits__terminations__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='circuits__terminations__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='circuits__terminations__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='circuits__terminations__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='circuits__terminations__site', queryset=Site.objects.all(), - label='Site', + label=_('Site'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='circuits__terminations__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) asn_id = django_filters.ModelMultipleChoiceFilter( field_name='asns', queryset=ASN.objects.all(), - label='ASN (ID)', + label=_('ASN (ID)'), ) class Meta: @@ -80,13 +81,13 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): class ProviderNetworkFilterSet(NetBoxModelFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( queryset=Provider.objects.all(), - label='Provider (ID)', + label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider__slug', queryset=Provider.objects.all(), to_field_name='slug', - label='Provider (slug)', + label=_('Provider (slug)'), ) class Meta: @@ -114,28 +115,28 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet): class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): provider_id = django_filters.ModelMultipleChoiceFilter( queryset=Provider.objects.all(), - label='Provider (ID)', + label=_('Provider (ID)'), ) provider = django_filters.ModelMultipleChoiceFilter( field_name='provider__slug', queryset=Provider.objects.all(), to_field_name='slug', - label='Provider (slug)', + label=_('Provider (slug)'), ) provider_network_id = django_filters.ModelMultipleChoiceFilter( field_name='terminations__provider_network', queryset=ProviderNetwork.objects.all(), - label='ProviderNetwork (ID)', + label=_('ProviderNetwork (ID)'), ) type_id = django_filters.ModelMultipleChoiceFilter( queryset=CircuitType.objects.all(), - label='Circuit type (ID)', + label=_('Circuit type (ID)'), ) type = django_filters.ModelMultipleChoiceFilter( field_name='type__slug', queryset=CircuitType.objects.all(), to_field_name='slug', - label='Circuit type (slug)', + label=_('Circuit type (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=CircuitStatusChoices, @@ -145,38 +146,38 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte queryset=Region.objects.all(), field_name='terminations__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='terminations__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='terminations__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='terminations__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='terminations__site', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='terminations__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) class Meta: @@ -199,25 +200,25 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) circuit_id = django_filters.ModelMultipleChoiceFilter( queryset=Circuit.objects.all(), - label='Circuit', + label=_('Circuit'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) provider_network_id = django_filters.ModelMultipleChoiceFilter( queryset=ProviderNetwork.objects.all(), - label='ProviderNetwork (ID)', + label=_('ProviderNetwork (ID)'), ) class Meta: diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py index 6e9ae516c..e1fe6338d 100644 --- a/netbox/circuits/forms/bulk_edit.py +++ b/netbox/circuits/forms/bulk_edit.py @@ -28,7 +28,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): account = forms.CharField( max_length=30, required=False, - label='Account number' + label=_('Account number') ) description = forms.CharField( max_length=200, @@ -36,7 +36,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = Provider @@ -56,7 +56,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): service_id = forms.CharField( max_length=100, required=False, - label='Service ID' + label=_('Service ID') ) description = forms.CharField( max_length=200, @@ -64,7 +64,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = ProviderNetwork @@ -118,7 +118,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm): ) commit_rate = forms.IntegerField( required=False, - label='Commit rate (Kbps)' + label=_('Commit rate (Kbps)') ) description = forms.CharField( max_length=100, @@ -126,7 +126,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = Circuit diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index 4976e2d9b..97b6af428 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -1,5 +1,6 @@ from circuits.choices import CircuitStatusChoices from circuits.models import * +from django.utils.translation import gettext as _ from netbox.forms import NetBoxModelCSVForm from tenancy.models import Tenant from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField @@ -26,7 +27,7 @@ class ProviderNetworkCSVForm(NetBoxModelCSVForm): provider = CSVModelChoiceField( queryset=Provider.objects.all(), to_field_name='name', - help_text='Assigned provider' + help_text=_('Assigned provider') ) class Meta: @@ -43,7 +44,7 @@ class CircuitTypeCSVForm(NetBoxModelCSVForm): model = CircuitType fields = ('name', 'slug', 'description', 'tags') help_texts = { - 'name': 'Name of circuit type', + 'name': _('Name of circuit type'), } @@ -51,22 +52,22 @@ class CircuitCSVForm(NetBoxModelCSVForm): provider = CSVModelChoiceField( queryset=Provider.objects.all(), to_field_name='name', - help_text='Assigned provider' + help_text=_('Assigned provider') ) type = CSVModelChoiceField( queryset=CircuitType.objects.all(), to_field_name='name', - help_text='Type of circuit' + help_text=_('Type of circuit') ) status = CSVChoiceField( choices=CircuitStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index ab1b6bca2..890462aaa 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -39,7 +39,7 @@ class ProviderForm(NetBoxModelForm): 'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags', ] help_texts = { - 'name': "Full name of the provider", + 'name': _("Full name of the provider"), } @@ -98,8 +98,8 @@ class CircuitForm(TenancyForm, NetBoxModelForm): 'tenant_group', 'tenant', 'comments', 'tags', ] help_texts = { - 'cid': "Unique circuit ID", - 'commit_rate': "Committed rate", + 'cid': _("Unique circuit ID"), + 'commit_rate': _("Committed rate"), } widgets = { 'status': StaticSelect(), @@ -157,9 +157,9 @@ class CircuitTerminationForm(NetBoxModelForm): 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags', ] help_texts = { - 'port_speed': "Physical circuit speed", - 'xconnect_id': "ID of the local cross-connect", - 'pp_info': "Patch panel ID and port number(s)" + 'port_speed': _("Physical circuit speed"), + 'xconnect_id': _("ID of the local cross-connect"), + 'pp_info': _("Patch panel ID and port number(s)") } widgets = { 'term_side': StaticSelect(), diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 9d302bb8e..ebba74738 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -3,6 +3,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse +from django.utils.translation import gettext as _ from circuits.choices import * from dcim.models import CabledObjectModel @@ -168,7 +169,7 @@ class CircuitTermination( blank=True, null=True, verbose_name='Upstream speed (Kbps)', - help_text='Upstream speed, if different from port speed' + help_text=_('Upstream speed, if different from port speed') ) xconnect_id = models.CharField( max_length=50, diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 33d79612a..4b8c95a73 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -1,6 +1,7 @@ import decimal from django.contrib.contenttypes.models import ContentType +from django.utils.translation import gettext as _ from drf_yasg.utils import swagger_serializer_method from rest_framework import serializers from timezone_field.rest_framework import TimeZoneSerializerField @@ -197,7 +198,7 @@ class RackSerializer(NetBoxModelSerializer): status = ChoiceField(choices=RackStatusChoices, required=False) role = NestedRackRoleSerializer(required=False, allow_null=True) type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False) - facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label='Facility ID', + facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label=_('Facility ID'), default=None) width = ChoiceField(choices=RackWidthChoices, required=False) outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False) @@ -311,7 +312,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer): u_height = serializers.DecimalField( max_digits=4, decimal_places=1, - label='Position (U)', + label=_('Position (U)'), min_value=0, default=1.0 ) @@ -636,7 +637,7 @@ class DeviceSerializer(NetBoxModelSerializer): max_digits=4, decimal_places=1, allow_null=True, - label='Position (U)', + label=_('Position (U)'), min_value=decimal.Decimal(0.5), default=None ) diff --git a/netbox/dcim/filtersets.py b/netbox/dcim/filtersets.py index 88d84a7ab..53576d017 100644 --- a/netbox/dcim/filtersets.py +++ b/netbox/dcim/filtersets.py @@ -1,5 +1,6 @@ import django_filters from django.contrib.auth.models import User +from django.utils.translation import gettext as _ from extras.filtersets import LocalConfigContextFilterSet from ipam.models import ASN, VRF @@ -72,13 +73,13 @@ __all__ = ( class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=Region.objects.all(), - label='Parent region (ID)', + label=_('Parent region (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=Region.objects.all(), to_field_name='slug', - label='Parent region (slug)', + label=_('Parent region (slug)'), ) class Meta: @@ -89,13 +90,13 @@ class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=SiteGroup.objects.all(), - label='Parent site group (ID)', + label=_('Parent site group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=SiteGroup.objects.all(), to_field_name='slug', - label='Parent site group (slug)', + label=_('Parent site group (slug)'), ) class Meta: @@ -112,36 +113,36 @@ class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe queryset=Region.objects.all(), field_name='region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='group', lookup_expr='in', - label='Group (ID)', + label=_('Group (ID)'), ) group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), lookup_expr='in', to_field_name='slug', - label='Group (slug)', + label=_('Group (slug)'), ) asn = django_filters.ModelMultipleChoiceFilter( field_name='asns__asn', queryset=ASN.objects.all(), to_field_name='asn', - label='AS (ID)', + label=_('AS (ID)'), ) asn_id = django_filters.ModelMultipleChoiceFilter( field_name='asns', queryset=ASN.objects.all(), - label='AS (ID)', + label=_('AS (ID)'), ) class Meta: @@ -173,50 +174,50 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalM queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) parent_id = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='parent', lookup_expr='in', - label='Location (ID)', + label=_('Location (ID)'), ) parent = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='parent', lookup_expr='in', to_field_name='slug', - label='Location (slug)', + label=_('Location (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=LocationStatusChoices, @@ -248,50 +249,50 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) location_id = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='location', lookup_expr='in', - label='Location (ID)', + label=_('Location (ID)'), ) location = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='location', lookup_expr='in', to_field_name='slug', - label='Location (slug)', + label=_('Location (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=RackStatusChoices, @@ -305,13 +306,13 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=RackRole.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=RackRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) serial = MultiValueCharFilter( lookup_expr='iexact' @@ -339,67 +340,67 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe class RackReservationFilterSet(NetBoxModelFilterSet, TenancyFilterSet): rack_id = django_filters.ModelMultipleChoiceFilter( queryset=Rack.objects.all(), - label='Rack (ID)', + label=_('Rack (ID)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='rack__site', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='rack__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='rack__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='rack__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='rack__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='rack__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) location_id = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='rack__location', lookup_expr='in', - label='Location (ID)', + label=_('Location (ID)'), ) location = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='rack__location', lookup_expr='in', to_field_name='slug', - label='Location (slug)', + label=_('Location (slug)'), ) user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), - label='User (ID)', + label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), to_field_name='username', - label='User (name)', + label=_('User (name)'), ) class Meta: @@ -427,57 +428,57 @@ class ManufacturerFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet) class DeviceTypeFilterSet(NetBoxModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) has_front_image = django_filters.BooleanFilter( - label='Has a front image', + label=_('Has a front image'), method='_has_front_image' ) has_rear_image = django_filters.BooleanFilter( - label='Has a rear image', + label=_('Has a rear image'), method='_has_rear_image' ) console_ports = django_filters.BooleanFilter( method='_console_ports', - label='Has console ports', + label=_('Has console ports'), ) console_server_ports = django_filters.BooleanFilter( method='_console_server_ports', - label='Has console server ports', + label=_('Has console server ports'), ) power_ports = django_filters.BooleanFilter( method='_power_ports', - label='Has power ports', + label=_('Has power ports'), ) power_outlets = django_filters.BooleanFilter( method='_power_outlets', - label='Has power outlets', + label=_('Has power outlets'), ) interfaces = django_filters.BooleanFilter( method='_interfaces', - label='Has interfaces', + label=_('Has interfaces'), ) pass_through_ports = django_filters.BooleanFilter( method='_pass_through_ports', - label='Has pass-through ports', + label=_('Has pass-through ports'), ) module_bays = django_filters.BooleanFilter( method='_module_bays', - label='Has module bays', + label=_('Has module bays'), ) device_bays = django_filters.BooleanFilter( method='_device_bays', - label='Has device bays', + label=_('Has device bays'), ) inventory_items = django_filters.BooleanFilter( method='_inventory_items', - label='Has inventory items', + label=_('Has inventory items'), ) class Meta: @@ -542,37 +543,37 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet): class ModuleTypeFilterSet(NetBoxModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) console_ports = django_filters.BooleanFilter( method='_console_ports', - label='Has console ports', + label=_('Has console ports'), ) console_server_ports = django_filters.BooleanFilter( method='_console_server_ports', - label='Has console server ports', + label=_('Has console server ports'), ) power_ports = django_filters.BooleanFilter( method='_power_ports', - label='Has power ports', + label=_('Has power ports'), ) power_outlets = django_filters.BooleanFilter( method='_power_outlets', - label='Has power outlets', + label=_('Has power outlets'), ) interfaces = django_filters.BooleanFilter( method='_interfaces', - label='Has interfaces', + label=_('Has interfaces'), ) pass_through_ports = django_filters.BooleanFilter( method='_pass_through_ports', - label='Has pass-through ports', + label=_('Has pass-through ports'), ) class Meta: @@ -614,12 +615,12 @@ class ModuleTypeFilterSet(NetBoxModelFilterSet): class DeviceTypeComponentFilterSet(django_filters.FilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) devicetype_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), field_name='device_type_id', - label='Device type (ID)', + label=_('Device type (ID)'), ) def search(self, queryset, name, value): @@ -632,7 +633,7 @@ class ModularDeviceTypeComponentFilterSet(DeviceTypeComponentFilterSet): moduletype_id = django_filters.ModelMultipleChoiceFilter( queryset=ModuleType.objects.all(), field_name='module_type_id', - label='Module type (ID)', + label=_('Module type (ID)'), ) @@ -724,27 +725,27 @@ class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponent class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemTemplate.objects.all(), - label='Parent inventory item (ID)', + label=_('Parent inventory item (ID)'), ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemRole.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=InventoryItemRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) component_type = ContentTypeFilter() component_id = MultiValueNumberFilter() @@ -775,13 +776,13 @@ class PlatformFilterSet(OrganizationalModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer', queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) class Meta: @@ -793,106 +794,106 @@ class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilter manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='device_type__manufacturer', queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='device_type__manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) device_type = django_filters.ModelMultipleChoiceFilter( field_name='device_type__slug', queryset=DeviceType.objects.all(), to_field_name='slug', - label='Device type (slug)', + label=_('Device type (slug)'), ) device_type_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceType.objects.all(), - label='Device type (ID)', + label=_('Device type (ID)'), ) role_id = django_filters.ModelMultipleChoiceFilter( field_name='device_role_id', queryset=DeviceRole.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='device_role__slug', queryset=DeviceRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) parent_device_id = django_filters.ModelMultipleChoiceFilter( field_name='parent_bay__device', queryset=Device.objects.all(), - label='Parent Device (ID)', + label=_('Parent Device (ID)'), ) platform_id = django_filters.ModelMultipleChoiceFilter( queryset=Platform.objects.all(), - label='Platform (ID)', + label=_('Platform (ID)'), ) platform = django_filters.ModelMultipleChoiceFilter( field_name='platform__slug', queryset=Platform.objects.all(), to_field_name='slug', - label='Platform (slug)', + label=_('Platform (slug)'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site name (slug)', + label=_('Site name (slug)'), ) location_id = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='location', lookup_expr='in', - label='Location (ID)', + label=_('Location (ID)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='rack', queryset=Rack.objects.all(), - label='Rack (ID)', + label=_('Rack (ID)'), ) cluster_id = django_filters.ModelMultipleChoiceFilter( queryset=Cluster.objects.all(), - label='VM cluster (ID)', + label=_('VM cluster (ID)'), ) model = django_filters.ModelMultipleChoiceFilter( field_name='device_type__slug', queryset=DeviceType.objects.all(), to_field_name='slug', - label='Device model (slug)', + label=_('Device model (slug)'), ) name = MultiValueCharFilter( lookup_expr='iexact' @@ -903,59 +904,59 @@ class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilter ) is_full_depth = django_filters.BooleanFilter( field_name='device_type__is_full_depth', - label='Is full depth', + label=_('Is full depth'), ) mac_address = MultiValueMACAddressFilter( field_name='interfaces__mac_address', - label='MAC address', + label=_('MAC address'), ) serial = MultiValueCharFilter( lookup_expr='iexact' ) has_primary_ip = django_filters.BooleanFilter( method='_has_primary_ip', - label='Has a primary IP', + label=_('Has a primary IP'), ) virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_chassis', queryset=VirtualChassis.objects.all(), - label='Virtual chassis (ID)', + label=_('Virtual chassis (ID)'), ) virtual_chassis_member = django_filters.BooleanFilter( method='_virtual_chassis_member', - label='Is a virtual chassis member' + label=_('Is a virtual chassis member') ) console_ports = django_filters.BooleanFilter( method='_console_ports', - label='Has console ports', + label=_('Has console ports'), ) console_server_ports = django_filters.BooleanFilter( method='_console_server_ports', - label='Has console server ports', + label=_('Has console server ports'), ) power_ports = django_filters.BooleanFilter( method='_power_ports', - label='Has power ports', + label=_('Has power ports'), ) power_outlets = django_filters.BooleanFilter( method='_power_outlets', - label='Has power outlets', + label=_('Has power outlets'), ) interfaces = django_filters.BooleanFilter( method='_interfaces', - label='Has interfaces', + label=_('Has interfaces'), ) pass_through_ports = django_filters.BooleanFilter( method='_pass_through_ports', - label='Has pass-through ports', + label=_('Has pass-through ports'), ) module_bays = django_filters.BooleanFilter( method='_module_bays', - label='Has module bays', + label=_('Has module bays'), ) device_bays = django_filters.BooleanFilter( method='_device_bays', - label='Has device bays', + label=_('Has device bays'), ) class Meta: @@ -1052,34 +1053,34 @@ class ModuleFilterSet(NetBoxModelFilterSet): manufacturer_id = django_filters.ModelMultipleChoiceFilter( field_name='module_type__manufacturer', queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='module_type__manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) module_type_id = django_filters.ModelMultipleChoiceFilter( field_name='module_type', queryset=ModuleType.objects.all(), - label='Module type (ID)', + label=_('Module type (ID)'), ) module_type = django_filters.ModelMultipleChoiceFilter( field_name='module_type__model', queryset=ModuleType.objects.all(), to_field_name='model', - label='Module type (model)', + label=_('Module type (model)'), ) module_bay_id = django_filters.ModelMultipleChoiceFilter( field_name='module_bay', queryset=ModuleBay.objects.all(), to_field_name='id', - label='Module Bay (ID)' + label=_('Module Bay (ID)') ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), - label='Device (ID)', + label=_('Device (ID)'), ) serial = MultiValueCharFilter( lookup_expr='iexact' @@ -1102,87 +1103,87 @@ class ModuleFilterSet(NetBoxModelFilterSet): class DeviceComponentFilterSet(django_filters.FilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='device__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='device__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='device__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='device__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='device__site', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='device__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site name (slug)', + label=_('Site name (slug)'), ) location_id = django_filters.ModelMultipleChoiceFilter( field_name='device__location', queryset=Location.objects.all(), - label='Location (ID)', + label=_('Location (ID)'), ) location = django_filters.ModelMultipleChoiceFilter( field_name='device__location__slug', queryset=Location.objects.all(), to_field_name='slug', - label='Location (slug)', + label=_('Location (slug)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='device__rack', queryset=Rack.objects.all(), - label='Rack (ID)', + label=_('Rack (ID)'), ) rack = django_filters.ModelMultipleChoiceFilter( field_name='device__rack__name', queryset=Rack.objects.all(), to_field_name='name', - label='Rack (name)', + label=_('Rack (name)'), ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), - label='Device (ID)', + label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), to_field_name='name', - label='Device (name)', + label=_('Device (name)'), ) virtual_chassis_id = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis', queryset=VirtualChassis.objects.all(), - label='Virtual Chassis (ID)' + label=_('Virtual Chassis (ID)') ) virtual_chassis = django_filters.ModelMultipleChoiceFilter( field_name='device__virtual_chassis__name', queryset=VirtualChassis.objects.all(), to_field_name='name', - label='Virtual Chassis', + label=_('Virtual Chassis'), ) def search(self, queryset, name, value): @@ -1202,7 +1203,7 @@ class ModularDeviceComponentFilterSet(DeviceComponentFilterSet): """ module_id = django_filters.ModelMultipleChoiceFilter( queryset=Module.objects.all(), - label='Module (ID)', + label=_('Module (ID)'), ) @@ -1314,31 +1315,31 @@ class InterfaceFilterSet( device = MultiValueCharFilter( method='filter_device', field_name='name', - label='Device', + label=_('Device'), ) device_id = MultiValueNumberFilter( method='filter_device_id', field_name='pk', - label='Device (ID)', + label=_('Device (ID)'), ) kind = django_filters.CharFilter( method='filter_kind', - label='Kind of interface', + label=_('Kind of interface'), ) parent_id = django_filters.ModelMultipleChoiceFilter( field_name='parent', queryset=Interface.objects.all(), - label='Parent interface (ID)', + label=_('Parent interface (ID)'), ) bridge_id = django_filters.ModelMultipleChoiceFilter( field_name='bridge', queryset=Interface.objects.all(), - label='Bridged interface (ID)', + label=_('Bridged interface (ID)'), ) lag_id = django_filters.ModelMultipleChoiceFilter( field_name='lag', queryset=Interface.objects.all(), - label='LAG interface (ID)', + label=_('LAG interface (ID)'), ) speed = MultiValueNumberFilter() duplex = django_filters.MultipleChoiceFilter( @@ -1354,11 +1355,11 @@ class InterfaceFilterSet( ) vlan_id = django_filters.CharFilter( method='filter_vlan_id', - label='Assigned VLAN' + label=_('Assigned VLAN') ) vlan = django_filters.CharFilter( method='filter_vlan', - label='Assigned VID' + label=_('Assigned VID') ) type = django_filters.MultipleChoiceFilter( choices=InterfaceTypeChoices, @@ -1373,13 +1374,13 @@ class InterfaceFilterSet( vrf_id = django_filters.ModelMultipleChoiceFilter( field_name='vrf', queryset=VRF.objects.all(), - label='VRF', + label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) vdc_id = django_filters.ModelMultipleChoiceFilter( field_name='vdcs', @@ -1501,27 +1502,27 @@ class DeviceBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet): class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItem.objects.all(), - label='Parent inventory item (ID)', + label=_('Parent inventory item (ID)'), ) manufacturer_id = django_filters.ModelMultipleChoiceFilter( queryset=Manufacturer.objects.all(), - label='Manufacturer (ID)', + label=_('Manufacturer (ID)'), ) manufacturer = django_filters.ModelMultipleChoiceFilter( field_name='manufacturer__slug', queryset=Manufacturer.objects.all(), to_field_name='slug', - label='Manufacturer (slug)', + label=_('Manufacturer (slug)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=InventoryItemRole.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=InventoryItemRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) component_type = ContentTypeFilter() component_id = MultiValueNumberFilter() @@ -1556,61 +1557,61 @@ class InventoryItemRoleFilterSet(OrganizationalModelFilterSet): class VirtualChassisFilterSet(NetBoxModelFilterSet): master_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), - label='Master (ID)', + label=_('Master (ID)'), ) master = django_filters.ModelMultipleChoiceFilter( field_name='master__name', queryset=Device.objects.all(), to_field_name='name', - label='Master (name)', + label=_('Master (name)'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='master__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='master__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='master__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='master__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='master__site', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='master__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site name (slug)', + label=_('Site name (slug)'), ) tenant_id = django_filters.ModelMultipleChoiceFilter( field_name='master__tenant', queryset=Tenant.objects.all(), - label='Tenant (ID)', + label=_('Tenant (ID)'), ) tenant = django_filters.ModelMultipleChoiceFilter( field_name='master__tenant__slug', queryset=Tenant.objects.all(), to_field_name='slug', - label='Tenant (slug)', + label=_('Tenant (slug)'), ) class Meta: @@ -1709,43 +1710,43 @@ class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site name (slug)', + label=_('Site name (slug)'), ) location_id = TreeNodeMultipleChoiceFilter( queryset=Location.objects.all(), field_name='location', lookup_expr='in', - label='Location (ID)', + label=_('Location (ID)'), ) class Meta: @@ -1766,47 +1767,47 @@ class PowerFeedFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet, PathEndpoi queryset=Region.objects.all(), field_name='power_panel__site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='power_panel__site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='power_panel__site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='power_panel__site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='power_panel__site', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='power_panel__site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site name (slug)', + label=_('Site name (slug)'), ) power_panel_id = django_filters.ModelMultipleChoiceFilter( queryset=PowerPanel.objects.all(), - label='Power panel (ID)', + label=_('Power panel (ID)'), ) rack_id = django_filters.ModelMultipleChoiceFilter( field_name='rack', queryset=Rack.objects.all(), - label='Rack (ID)', + label=_('Rack (ID)'), ) status = django_filters.MultipleChoiceFilter( choices=PowerFeedStatusChoices, @@ -1836,7 +1837,7 @@ class PowerFeedFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet, PathEndpoi class ConnectionFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) site_id = MultiValueNumberFilter( method='filter_connections', diff --git a/netbox/dcim/forms/bulk_create.py b/netbox/dcim/forms/bulk_create.py index f6bc27079..11fdfa6d2 100644 --- a/netbox/dcim/forms/bulk_create.py +++ b/netbox/dcim/forms/bulk_create.py @@ -1,6 +1,7 @@ from django import forms from dcim.models import * +from django.utils.translation import gettext as _ from extras.forms import CustomFieldsMixin from extras.models import Tag from utilities.forms import BootstrapMixin, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model @@ -105,9 +106,9 @@ class ModuleBayBulkCreateForm(DeviceBulkAddComponentForm): field_order = ('name', 'label', 'position_pattern', 'description', 'tags') replication_fields = ('name', 'label', 'position') position_pattern = ExpandableNameField( - label='Position', + label=_('Position'), required=False, - help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)' + help_text=_('Alphanumeric ranges are supported. (Must match the number of names being created.)') ) diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index 7a81ae7fb..c21988b45 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -1,6 +1,6 @@ from django import forms -from django.utils.translation import gettext as _ from django.contrib.auth.models import User +from django.utils.translation import gettext as _ from timezone_field import TimeZoneFormField from dcim.choices import * @@ -126,7 +126,7 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): ) contact_email = forms.EmailField( required=False, - label='Contact E-mail' + label=_('Contact E-mail') ) time_zone = TimeZoneFormField( choices=add_blank_choice(TimeZoneFormField().choices), @@ -248,7 +248,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): serial = forms.CharField( max_length=50, required=False, - label='Serial Number' + label=_('Serial Number') ) asset_tag = forms.CharField( max_length=50, @@ -266,12 +266,12 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): ) u_height = forms.IntegerField( required=False, - label='Height (U)' + label=_('Height (U)') ) desc_units = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect, - label='Descending units' + label=_('Descending units') ) outer_width = forms.IntegerField( required=False, @@ -380,7 +380,7 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): is_full_depth = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), - label='Is full depth' + label=_('Is full depth') ) airflow = forms.ChoiceField( choices=add_blank_choice(DeviceAirflowChoices), @@ -456,7 +456,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): vm_role = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect, - label='VM role' + label=_('VM role') ) description = forms.CharField( max_length=200, @@ -540,7 +540,7 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): serial = forms.CharField( max_length=50, required=False, - label='Serial Number' + label=_('Serial Number') ) description = forms.CharField( max_length=200, @@ -577,7 +577,7 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): serial = forms.CharField( max_length=50, required=False, - label='Serial Number' + label=_('Serial Number') ) description = forms.CharField( max_length=200, @@ -767,7 +767,7 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = PowerFeed @@ -838,12 +838,12 @@ class PowerPortTemplateBulkEditForm(BulkEditForm): maximum_draw = forms.IntegerField( min_value=1, required=False, - help_text="Maximum power draw (watts)" + help_text=_("Maximum power draw (watts)") ) allocated_draw = forms.IntegerField( min_value=1, required=False, - help_text="Allocated power draw (watts)" + help_text=_("Allocated power draw (watts)") ) description = forms.CharField( required=False @@ -916,7 +916,7 @@ class InterfaceTemplateBulkEditForm(BulkEditForm): mgmt_only = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect, - label='Management only' + label=_('Management only') ) description = forms.CharField( required=False @@ -926,14 +926,14 @@ class InterfaceTemplateBulkEditForm(BulkEditForm): required=False, initial='', widget=StaticSelect(), - label='PoE mode' + label=_('PoE mode') ) poe_type = forms.ChoiceField( choices=add_blank_choice(InterfacePoETypeChoices), required=False, initial='', widget=StaticSelect(), - label='PoE type' + label=_('PoE type') ) nullable_fields = ('label', 'description', 'poe_mode', 'poe_type') @@ -1174,31 +1174,31 @@ class InterfaceBulkEditForm( query_params={ 'type': 'lag', }, - label='LAG' + label=_('LAG') ) speed = forms.IntegerField( required=False, widget=SelectSpeedWidget(), - label='Speed' + label=_('Speed') ) mgmt_only = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect, - label='Management only' + label=_('Management only') ) poe_mode = forms.ChoiceField( choices=add_blank_choice(InterfacePoEModeChoices), required=False, initial='', widget=StaticSelect(), - label='PoE mode' + label=_('PoE mode') ) poe_type = forms.ChoiceField( choices=add_blank_choice(InterfacePoETypeChoices), required=False, initial='', widget=StaticSelect(), - label='PoE type' + label=_('PoE type') ) mark_connected = forms.NullBooleanField( required=False, @@ -1213,7 +1213,7 @@ class InterfaceBulkEditForm( vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group' + label=_('VLAN group') ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), @@ -1221,7 +1221,7 @@ class InterfaceBulkEditForm( query_params={ 'group_id': '$vlan_group', }, - label='Untagged VLAN' + label=_('Untagged VLAN') ) tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), @@ -1229,12 +1229,12 @@ class InterfaceBulkEditForm( query_params={ 'group_id': '$vlan_group', }, - label='Tagged VLANs' + label=_('Tagged VLANs') ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) model = Interface diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index 6073ee6fc..c7dbfcb17 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -3,6 +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 dcim.choices import * from dcim.constants import * @@ -52,7 +53,7 @@ class RegionCSVForm(NetBoxModelCSVForm): queryset=Region.objects.all(), required=False, to_field_name='name', - help_text='Name of parent region' + help_text=_('Name of parent region') ) class Meta: @@ -65,7 +66,7 @@ class SiteGroupCSVForm(NetBoxModelCSVForm): queryset=SiteGroup.objects.all(), required=False, to_field_name='name', - help_text='Name of parent site group' + help_text=_('Name of parent site group') ) class Meta: @@ -76,25 +77,25 @@ class SiteGroupCSVForm(NetBoxModelCSVForm): class SiteCSVForm(NetBoxModelCSVForm): status = CSVChoiceField( choices=SiteStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) region = CSVModelChoiceField( queryset=Region.objects.all(), required=False, to_field_name='name', - help_text='Assigned region' + help_text=_('Assigned region') ) group = CSVModelChoiceField( queryset=SiteGroup.objects.all(), required=False, to_field_name='name', - help_text='Assigned group' + help_text=_('Assigned group') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -105,7 +106,7 @@ class SiteCSVForm(NetBoxModelCSVForm): ) help_texts = { 'time_zone': mark_safe( - 'Time zone (available options)' + _('Time zone (available options)') ) } @@ -114,26 +115,26 @@ class LocationCSVForm(NetBoxModelCSVForm): site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', - help_text='Assigned site' + help_text=_('Assigned site') ) parent = CSVModelChoiceField( queryset=Location.objects.all(), required=False, to_field_name='name', - help_text='Parent location', + help_text=_('Parent location'), error_messages={ - 'invalid_choice': 'Location not found.', + 'invalid_choice': _('Location not found.'), } ) status = CSVChoiceField( choices=LocationStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -148,7 +149,7 @@ class RackRoleCSVForm(NetBoxModelCSVForm): model = RackRole fields = ('name', 'slug', 'color', 'description', 'tags') help_texts = { - 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), + 'color': mark_safe(_('RGB color in hexadecimal (e.g. 00ff00)')), } @@ -166,31 +167,31 @@ class RackCSVForm(NetBoxModelCSVForm): queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Name of assigned tenant' + help_text=_('Name of assigned tenant') ) status = CSVChoiceField( choices=RackStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) role = CSVModelChoiceField( queryset=RackRole.objects.all(), required=False, to_field_name='name', - help_text='Name of assigned role' + help_text=_('Name of assigned role') ) type = CSVChoiceField( choices=RackTypeChoices, required=False, - help_text='Rack type' + help_text=_('Rack type') ) width = forms.ChoiceField( choices=RackWidthChoices, - help_text='Rail-to-rail width (in inches)' + help_text=_('Rail-to-rail width (in inches)') ) outer_unit = CSVChoiceField( choices=RackDimensionUnitChoices, required=False, - help_text='Unit for outer dimensions' + help_text=_('Unit for outer dimensions') ) class Meta: @@ -215,29 +216,29 @@ class RackReservationCSVForm(NetBoxModelCSVForm): site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', - help_text='Parent site' + help_text=_('Parent site') ) location = CSVModelChoiceField( queryset=Location.objects.all(), to_field_name='name', required=False, - help_text="Rack's location (if any)" + help_text=_("Rack's location (if any)") ) rack = CSVModelChoiceField( queryset=Rack.objects.all(), to_field_name='name', - help_text='Rack' + help_text=_('Rack') ) units = SimpleArrayField( base_field=forms.IntegerField(), required=True, - help_text='Comma-separated list of individual unit numbers' + help_text=_('Comma-separated list of individual unit numbers') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -275,7 +276,7 @@ class DeviceRoleCSVForm(NetBoxModelCSVForm): model = DeviceRole fields = ('name', 'slug', 'color', 'vm_role', 'description', 'tags') help_texts = { - 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), + 'color': mark_safe(_('RGB color in hexadecimal (e.g. 00ff00)')), } @@ -285,7 +286,7 @@ class PlatformCSVForm(NetBoxModelCSVForm): queryset=Manufacturer.objects.all(), required=False, to_field_name='name', - help_text='Limit platform assignments to this manufacturer' + help_text=_('Limit platform assignments to this manufacturer') ) class Meta: @@ -297,45 +298,45 @@ class BaseDeviceCSVForm(NetBoxModelCSVForm): device_role = CSVModelChoiceField( queryset=DeviceRole.objects.all(), to_field_name='name', - help_text='Assigned role' + help_text=_('Assigned role') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) manufacturer = CSVModelChoiceField( queryset=Manufacturer.objects.all(), to_field_name='name', - help_text='Device type manufacturer' + help_text=_('Device type manufacturer') ) device_type = CSVModelChoiceField( queryset=DeviceType.objects.all(), to_field_name='model', - help_text='Device type model' + help_text=_('Device type model') ) platform = CSVModelChoiceField( queryset=Platform.objects.all(), required=False, to_field_name='name', - help_text='Assigned platform' + help_text=_('Assigned platform') ) status = CSVChoiceField( choices=DeviceStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) virtual_chassis = CSVModelChoiceField( queryset=VirtualChassis.objects.all(), to_field_name='name', required=False, - help_text='Virtual chassis' + help_text=_('Virtual chassis') ) cluster = CSVModelChoiceField( queryset=Cluster.objects.all(), to_field_name='name', required=False, - help_text='Virtualization cluster' + help_text=_('Virtualization cluster') ) class Meta: @@ -360,29 +361,29 @@ class DeviceCSVForm(BaseDeviceCSVForm): site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', - help_text='Assigned site' + help_text=_('Assigned site') ) location = CSVModelChoiceField( queryset=Location.objects.all(), to_field_name='name', required=False, - help_text="Assigned location (if any)" + help_text=_("Assigned location (if any)") ) rack = CSVModelChoiceField( queryset=Rack.objects.all(), to_field_name='name', required=False, - help_text="Assigned rack (if any)" + help_text=_("Assigned rack (if any)") ) face = CSVChoiceField( choices=DeviceFaceChoices, required=False, - help_text='Mounted rack face' + help_text=_('Mounted rack face') ) airflow = CSVChoiceField( choices=DeviceAirflowChoices, required=False, - help_text='Airflow direction' + help_text=_('Airflow direction') ) class Meta(BaseDeviceCSVForm.Meta): @@ -442,12 +443,12 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm): parent = CSVModelChoiceField( queryset=Device.objects.all(), to_field_name='name', - help_text='Parent device' + help_text=_('Parent device') ) device_bay = CSVModelChoiceField( queryset=DeviceBay.objects.all(), to_field_name='name', - help_text='Device bay in which this device is installed' + help_text=_('Device bay in which this device is installed') ) class Meta(BaseDeviceCSVForm.Meta): @@ -492,14 +493,14 @@ class ConsolePortCSVForm(NetBoxModelCSVForm): type = CSVChoiceField( choices=ConsolePortTypeChoices, required=False, - help_text='Port type' + help_text=_('Port type') ) speed = CSVTypedChoiceField( choices=ConsolePortSpeedChoices, coerce=int, empty_value=None, required=False, - help_text='Port speed in bps' + help_text=_('Port speed in bps') ) class Meta: @@ -515,14 +516,14 @@ class ConsoleServerPortCSVForm(NetBoxModelCSVForm): type = CSVChoiceField( choices=ConsolePortTypeChoices, required=False, - help_text='Port type' + help_text=_('Port type') ) speed = CSVTypedChoiceField( choices=ConsolePortSpeedChoices, coerce=int, empty_value=None, required=False, - help_text='Port speed in bps' + help_text=_('Port speed in bps') ) class Meta: @@ -538,7 +539,7 @@ class PowerPortCSVForm(NetBoxModelCSVForm): type = CSVChoiceField( choices=PowerPortTypeChoices, required=False, - help_text='Port type' + help_text=_('Port type') ) class Meta: @@ -556,18 +557,18 @@ class PowerOutletCSVForm(NetBoxModelCSVForm): type = CSVChoiceField( choices=PowerOutletTypeChoices, required=False, - help_text='Outlet type' + help_text=_('Outlet type') ) power_port = CSVModelChoiceField( queryset=PowerPort.objects.all(), required=False, to_field_name='name', - help_text='Local power port which feeds this outlet' + help_text=_('Local power port which feeds this outlet') ) feed_leg = CSVChoiceField( choices=PowerOutletFeedLegChoices, required=False, - help_text='Electrical phase (for three-phase circuits)' + help_text=_('Electrical phase (for three-phase circuits)') ) class Meta: @@ -606,23 +607,23 @@ class InterfaceCSVForm(NetBoxModelCSVForm): queryset=Interface.objects.all(), required=False, to_field_name='name', - help_text='Parent interface' + help_text=_('Parent interface') ) bridge = CSVModelChoiceField( queryset=Interface.objects.all(), required=False, to_field_name='name', - help_text='Bridged interface' + help_text=_('Bridged interface') ) lag = CSVModelChoiceField( queryset=Interface.objects.all(), required=False, to_field_name='name', - help_text='Parent LAG interface' + help_text=_('Parent LAG interface') ) type = CSVChoiceField( choices=InterfaceTypeChoices, - help_text='Physical medium' + help_text=_('Physical medium') ) duplex = CSVChoiceField( choices=InterfaceDuplexChoices, @@ -631,28 +632,28 @@ class InterfaceCSVForm(NetBoxModelCSVForm): poe_mode = CSVChoiceField( choices=InterfacePoEModeChoices, required=False, - help_text='PoE mode' + help_text=_('PoE mode') ) poe_type = CSVChoiceField( choices=InterfacePoETypeChoices, required=False, - help_text='PoE type' + help_text=_('PoE type') ) mode = CSVChoiceField( choices=InterfaceModeChoices, required=False, - help_text='IEEE 802.1Q operational mode (for L2 interfaces)' + help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)') ) vrf = CSVModelChoiceField( queryset=VRF.objects.all(), required=False, to_field_name='rd', - help_text='Assigned VRF' + help_text=_('Assigned VRF') ) rf_role = CSVChoiceField( choices=WirelessRoleChoices, required=False, - help_text='Wireless role (AP/station)' + help_text=_('Wireless role (AP/station)') ) class Meta: @@ -692,11 +693,11 @@ class FrontPortCSVForm(NetBoxModelCSVForm): rear_port = CSVModelChoiceField( queryset=RearPort.objects.all(), to_field_name='name', - help_text='Corresponding rear port' + help_text=_('Corresponding rear port') ) type = CSVChoiceField( choices=PortTypeChoices, - help_text='Physical medium classification' + help_text=_('Physical medium classification') ) class Meta: @@ -706,7 +707,7 @@ class FrontPortCSVForm(NetBoxModelCSVForm): 'description', 'tags' ) help_texts = { - 'rear_port_position': 'Mapped position on corresponding rear port', + 'rear_port_position': _('Mapped position on corresponding rear port'), } def __init__(self, *args, **kwargs): @@ -738,7 +739,7 @@ class RearPortCSVForm(NetBoxModelCSVForm): to_field_name='name' ) type = CSVChoiceField( - help_text='Physical medium classification', + help_text=_('Physical medium classification'), choices=PortTypeChoices, ) @@ -746,7 +747,7 @@ class RearPortCSVForm(NetBoxModelCSVForm): model = RearPort fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'tags') help_texts = { - 'positions': 'Number of front ports which may be mapped' + 'positions': _('Number of front ports which may be mapped') } @@ -770,9 +771,9 @@ class DeviceBayCSVForm(NetBoxModelCSVForm): queryset=Device.objects.all(), required=False, to_field_name='name', - help_text='Child device installed within this bay', + help_text=_('Child device installed within this bay'), error_messages={ - 'invalid_choice': 'Child device not found.', + 'invalid_choice': _('Child device not found.'), } ) @@ -826,7 +827,7 @@ class InventoryItemCSVForm(NetBoxModelCSVForm): queryset=Device.objects.all(), to_field_name='name', required=False, - help_text='Parent inventory item' + help_text=_('Parent inventory item') ) class Meta: @@ -863,7 +864,7 @@ class InventoryItemRoleCSVForm(NetBoxModelCSVForm): model = InventoryItemRole fields = ('name', 'slug', 'color', 'description') help_texts = { - 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), + 'color': mark_safe(_('RGB color in hexadecimal (e.g. 00ff00)')), } @@ -876,53 +877,53 @@ class CableCSVForm(NetBoxModelCSVForm): side_a_device = CSVModelChoiceField( queryset=Device.objects.all(), to_field_name='name', - help_text='Side A device' + help_text=_('Side A device') ) side_a_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, - help_text='Side A type' + help_text=_('Side A type') ) side_a_name = forms.CharField( - help_text='Side A component name' + help_text=_('Side A component name') ) # Termination B side_b_device = CSVModelChoiceField( queryset=Device.objects.all(), to_field_name='name', - help_text='Side B device' + help_text=_('Side B device') ) side_b_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=CABLE_TERMINATION_MODELS, - help_text='Side B type' + help_text=_('Side B type') ) side_b_name = forms.CharField( - help_text='Side B component name' + help_text=_('Side B component name') ) # Cable attributes status = CSVChoiceField( choices=LinkStatusChoices, required=False, - help_text='Connection status' + help_text=_('Connection status') ) type = CSVChoiceField( choices=CableTypeChoices, required=False, - help_text='Physical medium classification' + help_text=_('Physical medium classification') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) length_unit = CSVChoiceField( choices=CableLengthUnitChoices, required=False, - help_text='Length unit' + help_text=_('Length unit') ) class Meta: @@ -932,7 +933,7 @@ class CableCSVForm(NetBoxModelCSVForm): 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags', ] help_texts = { - 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), + 'color': mark_safe(_('RGB color in hexadecimal (e.g. 00ff00)')), } def _clean_side(self, side): @@ -981,7 +982,7 @@ class VirtualChassisCSVForm(NetBoxModelCSVForm): queryset=Device.objects.all(), to_field_name='name', required=False, - help_text='Master device' + help_text=_('Master device') ) class Meta: @@ -997,7 +998,7 @@ class PowerPanelCSVForm(NetBoxModelCSVForm): site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', - help_text='Name of parent site' + help_text=_('Name of parent site') ) location = CSVModelChoiceField( queryset=Location.objects.all(), @@ -1023,40 +1024,40 @@ class PowerFeedCSVForm(NetBoxModelCSVForm): site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', - help_text='Assigned site' + help_text=_('Assigned site') ) power_panel = CSVModelChoiceField( queryset=PowerPanel.objects.all(), to_field_name='name', - help_text='Upstream power panel' + help_text=_('Upstream power panel') ) location = CSVModelChoiceField( queryset=Location.objects.all(), to_field_name='name', required=False, - help_text="Rack's location (if any)" + help_text=_("Rack's location (if any)") ) rack = CSVModelChoiceField( queryset=Rack.objects.all(), to_field_name='name', required=False, - help_text='Rack' + help_text=_('Rack') ) status = CSVChoiceField( choices=PowerFeedStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) type = CSVChoiceField( choices=PowerFeedTypeChoices, - help_text='Primary or redundant' + help_text=_('Primary or redundant') ) supply = CSVChoiceField( choices=PowerFeedSupplyChoices, - help_text='Supply type (AC/DC)' + help_text=_('Supply type (AC/DC)') ) phase = CSVChoiceField( choices=PowerFeedPhaseChoices, - help_text='Single or three-phase' + help_text=_('Single or three-phase') ) class Meta: diff --git a/netbox/dcim/forms/common.py b/netbox/dcim/forms/common.py index f484b48e1..9d5232ddf 100644 --- a/netbox/dcim/forms/common.py +++ b/netbox/dcim/forms/common.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.choices import * from dcim.constants import * @@ -12,13 +13,13 @@ class InterfaceCommonForm(forms.Form): mac_address = forms.CharField( empty_value=None, required=False, - label='MAC address' + label=_('MAC address') ) mtu = forms.IntegerField( required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, - label='MTU' + label=_('MTU') ) def clean(self): diff --git a/netbox/dcim/forms/connections.py b/netbox/dcim/forms/connections.py index 537a89bad..ba5e51c41 100644 --- a/netbox/dcim/forms/connections.py +++ b/netbox/dcim/forms/connections.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from circuits.models import Circuit, CircuitTermination, Provider from dcim.models import * @@ -16,7 +17,7 @@ def get_cable_form(a_type, b_type): attrs[f'termination_{cable_end}_region'] = DynamicModelChoiceField( queryset=Region.objects.all(), - label='Region', + label=_('Region'), required=False, initial_params={ 'sites': f'$termination_{cable_end}_site' @@ -24,7 +25,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'termination_{cable_end}_sitegroup'] = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), - label='Site group', + label=_('Site group'), required=False, initial_params={ 'sites': f'$termination_{cable_end}_site' @@ -32,7 +33,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'termination_{cable_end}_site'] = DynamicModelChoiceField( queryset=Site.objects.all(), - label='Site', + label=_('Site'), required=False, query_params={ 'region_id': f'$termination_{cable_end}_region', @@ -41,7 +42,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'termination_{cable_end}_location'] = DynamicModelChoiceField( queryset=Location.objects.all(), - label='Location', + label=_('Location'), required=False, null_option='None', query_params={ @@ -54,7 +55,7 @@ def get_cable_form(a_type, b_type): attrs[f'termination_{cable_end}_rack'] = DynamicModelChoiceField( queryset=Rack.objects.all(), - label='Rack', + label=_('Rack'), required=False, null_option='None', initial_params={ @@ -67,7 +68,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'termination_{cable_end}_device'] = DynamicModelChoiceField( queryset=Device.objects.all(), - label='Device', + label=_('Device'), required=False, initial_params={ f'{term_cls._meta.model_name}s__in': f'${cable_end}_terminations' @@ -93,7 +94,7 @@ def get_cable_form(a_type, b_type): attrs[f'termination_{cable_end}_powerpanel'] = DynamicModelChoiceField( queryset=PowerPanel.objects.all(), - label='Power Panel', + label=_('Power Panel'), required=False, initial_params={ 'powerfeeds__in': f'${cable_end}_terminations' @@ -105,7 +106,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( queryset=term_cls.objects.all(), - label='Power Feed', + label=_('Power Feed'), disabled_indicator='_occupied', query_params={ 'power_panel_id': f'$termination_{cable_end}_powerpanel', @@ -117,7 +118,7 @@ def get_cable_form(a_type, b_type): attrs[f'termination_{cable_end}_provider'] = DynamicModelChoiceField( queryset=Provider.objects.all(), - label='Provider', + label=_('Provider'), initial_params={ 'circuits': f'$termination_{cable_end}_circuit' }, @@ -125,7 +126,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'termination_{cable_end}_circuit'] = DynamicModelChoiceField( queryset=Circuit.objects.all(), - label='Circuit', + label=_('Circuit'), initial_params={ 'terminations__in': f'${cable_end}_terminations' }, @@ -136,7 +137,7 @@ def get_cable_form(a_type, b_type): ) attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( queryset=term_cls.objects.all(), - label='Side', + label=_('Side'), disabled_indicator='_occupied', query_params={ 'circuit_id': f'$termination_{cable_end}_circuit', diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index da0148784..76d2d9204 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.utils.translation import gettext as _ from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType +from django.utils.translation import gettext as _ from timezone_field import TimeZoneFormField from dcim.choices import * @@ -163,14 +163,14 @@ class SiteForm(TenancyForm, NetBoxModelForm): 'time_zone': StaticSelect(), } help_texts = { - 'name': "Full name of the site", - 'facility': "Data center provider and facility (e.g. Equinix NY7)", - 'time_zone': "Local time zone", - 'description': "Short description (will appear in sites list)", - 'physical_address': "Physical location of the building (e.g. for GPS)", - 'shipping_address': "If different from the physical address", - 'latitude': "Latitude in decimal format (xx.yyyyyy)", - 'longitude': "Longitude in decimal format (xx.yyyyyy)" + 'name': _("Full name of the site"), + 'facility': _("Data center provider and facility (e.g. Equinix NY7)"), + 'time_zone': _("Local time zone"), + 'description': _("Short description (will appear in sites list)"), + 'physical_address': _("Physical location of the building (e.g. for GPS)"), + 'shipping_address': _("If different from the physical address"), + 'latitude': _("Latitude in decimal format (xx.yyyyyy)"), + 'longitude': _("Longitude in decimal format (xx.yyyyyy)") } @@ -282,10 +282,10 @@ class RackForm(TenancyForm, NetBoxModelForm): 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'description', 'comments', 'tags', ] help_texts = { - 'site': "The site at which the rack exists", - 'name': "Organizational rack name", - 'facility_id': "The unique rack ID assigned by the facility", - 'u_height': "Height in rack units", + 'site': _("The site at which the rack exists"), + 'name': _("Organizational rack name"), + 'facility_id': _("The unique rack ID assigned by the facility"), + 'u_height': _("Height in rack units"), } widgets = { 'status': StaticSelect(), @@ -335,7 +335,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): ) units = NumericArrayField( base_field=forms.IntegerField(), - help_text="Comma-separated list of numeric unit IDs. A range may be specified using a hyphen." + help_text=_("Comma-separated list of numeric unit IDs. A range may be specified using a hyphen.") ) user = forms.ModelChoiceField( queryset=User.objects.order_by( @@ -519,7 +519,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): ) position = forms.DecimalField( required=False, - help_text="The lowest-numbered unit occupied by the device", + help_text=_("The lowest-numbered unit occupied by the device"), widget=APISelect( api_url='/api/dcim/racks/{{rack}}/elevation/', attrs={ @@ -577,13 +577,13 @@ class DeviceForm(TenancyForm, NetBoxModelForm): ) vc_position = forms.IntegerField( required=False, - label='Position', - help_text="The position in the virtual chassis this device is identified by" + label=_('Position'), + help_text=_("The position in the virtual chassis this device is identified by") ) vc_priority = forms.IntegerField( required=False, - label='Priority', - help_text="The priority of the device in the virtual chassis" + label=_('Priority'), + help_text=_("The priority of the device in the virtual chassis") ) class Meta: @@ -595,10 +595,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm): 'description', 'comments', 'tags', 'local_context_data' ] help_texts = { - 'device_role': "The function this device serves", - 'serial': "Chassis serial number", - 'local_context_data': "Local config context data overwrites all source contexts in the final rendered " - "config context", + 'device_role': _("The function this device serves"), + 'serial': _("Chassis serial number"), + 'local_context_data': _("Local config context data overwrites all source contexts in the final rendered " + "config context"), } widgets = { 'face': StaticSelect(), @@ -695,13 +695,13 @@ class ModuleForm(NetBoxModelForm): replicate_components = forms.BooleanField( required=False, initial=True, - help_text="Automatically populate components associated with this module type" + help_text=_("Automatically populate components associated with this module type") ) adopt_components = forms.BooleanField( required=False, initial=False, - help_text="Adopt already existing components" + help_text=_("Adopt already existing components") ) fieldsets = ( @@ -1390,7 +1390,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): parent = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, - label='Parent interface', + label=_('Parent interface'), query_params={ 'device_id': '$device', } @@ -1398,7 +1398,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): bridge = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, - label='Bridged interface', + label=_('Bridged interface'), query_params={ 'device_id': '$device', } @@ -1406,7 +1406,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): lag = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, - label='LAG interface', + label=_('LAG interface'), query_params={ 'device_id': '$device', 'type': 'lag', @@ -1415,12 +1415,12 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): wireless_lan_group = DynamicModelChoiceField( queryset=WirelessLANGroup.objects.all(), required=False, - label='Wireless LAN group' + label=_('Wireless LAN group') ) wireless_lans = DynamicModelMultipleChoiceField( queryset=WirelessLAN.objects.all(), required=False, - label='Wireless LANs', + label=_('Wireless LANs'), query_params={ 'group_id': '$wireless_lan_group', } @@ -1428,12 +1428,12 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group' + label=_('VLAN group') ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, - label='Untagged VLAN', + label=_('Untagged VLAN'), query_params={ 'group_id': '$vlan_group', 'available_on_device': '$device', @@ -1442,7 +1442,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, - label='Tagged VLANs', + label=_('Tagged VLANs'), query_params={ 'group_id': '$vlan_group', 'available_on_device': '$device', @@ -1451,13 +1451,13 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) wwn = forms.CharField( empty_value=None, required=False, - label='WWN' + label=_('WWN') ) fieldsets = ( @@ -1495,8 +1495,8 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm): } help_texts = { 'mode': INTERFACE_MODE_HELP_TEXT, - 'rf_channel_frequency': "Populated by selected channel (if set)", - 'rf_channel_width': "Populated by selected channel (if set)", + 'rf_channel_frequency': _("Populated by selected channel (if set)"), + 'rf_channel_width': _("Populated by selected channel (if set)"), } @@ -1570,8 +1570,8 @@ class DeviceBayForm(DeviceComponentForm): class PopulateDeviceBayForm(BootstrapMixin, forms.Form): installed_device = forms.ModelChoiceField( queryset=Device.objects.all(), - label='Child Device', - help_text="Child devices must first be created and assigned to the site/rack of the parent device.", + label=_('Child Device'), + help_text=_("Child devices must first be created and assigned to the site/rack of the parent device."), widget=StaticSelect(), ) diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py index afdaa4fcc..6de193043 100644 --- a/netbox/dcim/forms/object_create.py +++ b/netbox/dcim/forms/object_create.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.models import * from netbox.forms import NetBoxModelForm @@ -39,7 +40,7 @@ class ComponentCreateForm(forms.Form): name = ExpandableNameField() label = ExpandableNameField( required=False, - help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' + help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)') ) # Identify the fields which support replication (i.e. ExpandableNameFields). This is referenced by @@ -97,8 +98,8 @@ class InterfaceTemplateCreateForm(ComponentCreateForm, model_forms.InterfaceTemp class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemplateForm): rear_port = forms.MultipleChoiceField( choices=[], - label='Rear ports', - help_text='Select one rear port assignment for each front port being created.', + label=_('Rear ports'), + help_text=_('Select one rear port assignment for each front port being created.'), ) # Override fieldsets from FrontPortTemplateForm to omit rear_port_position @@ -166,9 +167,9 @@ class DeviceBayTemplateCreateForm(ComponentCreateForm, model_forms.DeviceBayTemp class ModuleBayTemplateCreateForm(ComponentCreateForm, model_forms.ModuleBayTemplateForm): position = ExpandableNameField( - label='Position', + label=_('Position'), required=False, - help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' + help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)') ) replication_fields = ('name', 'label', 'position') @@ -226,8 +227,8 @@ class InterfaceCreateForm(ComponentCreateForm, model_forms.InterfaceForm): class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): rear_port = forms.MultipleChoiceField( choices=[], - label='Rear ports', - help_text='Select one rear port assignment for each front port being created.', + label=_('Rear ports'), + help_text=_('Select one rear port assignment for each front port being created.'), ) # Override fieldsets from FrontPortForm to omit rear_port_position @@ -290,9 +291,9 @@ class DeviceBayCreateForm(ComponentCreateForm, model_forms.DeviceBayForm): class ModuleBayCreateForm(ComponentCreateForm, model_forms.ModuleBayForm): position = ExpandableNameField( - label='Position', + label=_('Position'), required=False, - help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' + help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)') ) replication_fields = ('name', 'label', 'position') @@ -352,7 +353,7 @@ class VirtualChassisCreateForm(NetBoxModelForm): initial_position = forms.IntegerField( initial=1, required=False, - help_text='Position of the first member device. Increases by one for each additional member.' + help_text=_('Position of the first member device. Increases by one for each additional member.') ) class Meta: diff --git a/netbox/dcim/forms/object_import.py b/netbox/dcim/forms/object_import.py index 82ee093dd..920c0081f 100644 --- a/netbox/dcim/forms/object_import.py +++ b/netbox/dcim/forms/object_import.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices from dcim.models import * @@ -115,12 +116,12 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm): poe_mode = forms.ChoiceField( choices=InterfacePoEModeChoices, required=False, - label='PoE mode' + label=_('PoE mode') ) poe_type = forms.ChoiceField( choices=InterfacePoETypeChoices, required=False, - label='PoE type' + label=_('PoE type') ) class Meta: diff --git a/netbox/dcim/models/device_component_templates.py b/netbox/dcim/models/device_component_templates.py index 15389a2c0..3b136987d 100644 --- a/netbox/dcim/models/device_component_templates.py +++ b/netbox/dcim/models/device_component_templates.py @@ -3,6 +3,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models +from django.utils.translation import gettext as _ from mptt.models import MPTTModel, TreeForeignKey from dcim.choices import * @@ -52,7 +53,7 @@ class ComponentTemplateModel(WebhooksMixin, ChangeLoggedModel): label = models.CharField( max_length=64, blank=True, - help_text="Physical label" + help_text=_("Physical label") ) description = models.CharField( max_length=200, @@ -222,13 +223,13 @@ class PowerPortTemplate(ModularComponentTemplateModel): blank=True, null=True, validators=[MinValueValidator(1)], - help_text="Maximum power draw (watts)" + help_text=_("Maximum power draw (watts)") ) allocated_draw = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MinValueValidator(1)], - help_text="Allocated power draw (watts)" + help_text=_("Allocated power draw (watts)") ) component_model = PowerPort @@ -283,7 +284,7 @@ class PowerOutletTemplate(ModularComponentTemplateModel): max_length=50, choices=PowerOutletFeedLegChoices, blank=True, - help_text="Phase (for three-phase feeds)" + help_text=_("Phase (for three-phase feeds)") ) component_model = PowerOutlet @@ -526,7 +527,7 @@ class ModuleBayTemplate(ComponentTemplateModel): position = models.CharField( max_length=30, blank=True, - help_text='Identifier to reference when renaming installed components' + help_text=_('Identifier to reference when renaming installed components') ) component_model = ModuleBay @@ -621,7 +622,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel): max_length=50, verbose_name='Part ID', blank=True, - help_text='Manufacturer-assigned part identifier' + help_text=_('Manufacturer-assigned part identifier') ) objects = TreeManager() diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 23c820571..7b3534a4e 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -7,6 +7,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.db.models import Sum from django.urls import reverse +from django.utils.translation import gettext as _ from mptt.models import MPTTModel, TreeForeignKey from dcim.choices import * @@ -60,7 +61,7 @@ class ComponentModel(NetBoxModel): label = models.CharField( max_length=64, blank=True, - help_text="Physical label" + help_text=_("Physical label") ) description = models.CharField( max_length=200, @@ -129,7 +130,7 @@ class CabledObjectModel(models.Model): ) mark_connected = models.BooleanField( default=False, - help_text="Treat as if a cable is connected" + help_text=_("Treat as if a cable is connected") ) cable_terminations = GenericRelation( @@ -261,13 +262,13 @@ class ConsolePort(ModularComponentModel, CabledObjectModel, PathEndpoint): max_length=50, choices=ConsolePortTypeChoices, blank=True, - help_text='Physical port type' + help_text=_('Physical port type') ) speed = models.PositiveIntegerField( choices=ConsolePortSpeedChoices, blank=True, null=True, - help_text='Port speed in bits per second' + help_text=_('Port speed in bits per second') ) clone_fields = ('device', 'module', 'type', 'speed') @@ -284,13 +285,13 @@ class ConsoleServerPort(ModularComponentModel, CabledObjectModel, PathEndpoint): max_length=50, choices=ConsolePortTypeChoices, blank=True, - help_text='Physical port type' + help_text=_('Physical port type') ) speed = models.PositiveIntegerField( choices=ConsolePortSpeedChoices, blank=True, null=True, - help_text='Port speed in bits per second' + help_text=_('Port speed in bits per second') ) clone_fields = ('device', 'module', 'type', 'speed') @@ -311,19 +312,19 @@ class PowerPort(ModularComponentModel, CabledObjectModel, PathEndpoint): max_length=50, choices=PowerPortTypeChoices, blank=True, - help_text='Physical port type' + help_text=_('Physical port type') ) maximum_draw = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MinValueValidator(1)], - help_text="Maximum power draw (watts)" + help_text=_("Maximum power draw (watts)") ) allocated_draw = models.PositiveSmallIntegerField( blank=True, null=True, validators=[MinValueValidator(1)], - help_text="Allocated power draw (watts)" + help_text=_("Allocated power draw (watts)") ) clone_fields = ('device', 'module', 'maximum_draw', 'allocated_draw') @@ -420,7 +421,7 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint): max_length=50, choices=PowerOutletTypeChoices, blank=True, - help_text='Physical port type' + help_text=_('Physical port type') ) power_port = models.ForeignKey( to='dcim.PowerPort', @@ -433,7 +434,7 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint): max_length=50, choices=PowerOutletFeedLegChoices, blank=True, - help_text="Phase (for three-phase feeds)" + help_text=_("Phase (for three-phase feeds)") ) clone_fields = ('device', 'module', 'type', 'power_port', 'feed_leg') @@ -550,7 +551,7 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd mgmt_only = models.BooleanField( default=False, verbose_name='Management only', - help_text='This interface is used only for out-of-band management' + help_text=_('This interface is used only for out-of-band management') ) speed = models.PositiveIntegerField( blank=True, @@ -567,7 +568,7 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd null=True, blank=True, verbose_name='WWN', - help_text='64-bit World Wide Name' + help_text=_('64-bit World Wide Name') ) rf_role = models.CharField( max_length=30, @@ -970,7 +971,7 @@ class ModuleBay(ComponentModel): position = models.CharField( max_length=30, blank=True, - help_text='Identifier to reference when renaming installed components' + help_text=_('Identifier to reference when renaming installed components') ) clone_fields = ('device',) @@ -1084,7 +1085,7 @@ class InventoryItem(MPTTModel, ComponentModel): max_length=50, verbose_name='Part ID', blank=True, - help_text='Manufacturer-assigned part identifier' + help_text=_('Manufacturer-assigned part identifier') ) serial = models.CharField( max_length=50, @@ -1097,11 +1098,11 @@ class InventoryItem(MPTTModel, ComponentModel): blank=True, null=True, verbose_name='Asset tag', - help_text='A unique tag used to identify this item' + help_text=_('A unique tag used to identify this item') ) discovered = models.BooleanField( default=False, - help_text='This item was automatically discovered' + help_text=_('This item was automatically discovered') ) objects = TreeManager() diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index afa792ffb..b71a185b7 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -12,6 +12,7 @@ from django.db.models import F, ProtectedError from django.db.models.functions import Lower from django.urls import reverse from django.utils.safestring import mark_safe +from django.utils.translation import gettext as _ from dcim.choices import * from dcim.constants import * @@ -84,7 +85,7 @@ class DeviceType(PrimaryModel, WeightMixin): part_number = models.CharField( max_length=50, blank=True, - help_text='Discrete part number (optional)' + help_text=_('Discrete part number (optional)') ) u_height = models.DecimalField( max_digits=4, @@ -95,15 +96,15 @@ class DeviceType(PrimaryModel, WeightMixin): is_full_depth = models.BooleanField( default=True, verbose_name='Is full depth', - help_text='Device consumes both front and rear rack faces' + help_text=_('Device consumes both front and rear rack faces') ) subdevice_role = models.CharField( max_length=50, choices=SubdeviceRoleChoices, blank=True, verbose_name='Parent/child status', - help_text='Parent devices house child devices in device bays. Leave blank ' - 'if this device type is neither a parent nor a child.' + help_text=_('Parent devices house child devices in device bays. Leave blank ' + 'if this device type is neither a parent nor a child.') ) airflow = models.CharField( max_length=50, @@ -314,7 +315,7 @@ class ModuleType(PrimaryModel, WeightMixin): part_number = models.CharField( max_length=50, blank=True, - help_text='Discrete part number (optional)' + help_text=_('Discrete part number (optional)') ) # Generic relations @@ -400,7 +401,7 @@ class DeviceRole(OrganizationalModel): vm_role = models.BooleanField( default=True, verbose_name='VM Role', - help_text='Virtual machines may be assigned to this role' + help_text=_('Virtual machines may be assigned to this role') ) def get_absolute_url(self): @@ -419,19 +420,19 @@ class Platform(OrganizationalModel): related_name='platforms', blank=True, null=True, - help_text='Optionally limit this platform to devices of a certain manufacturer' + help_text=_('Optionally limit this platform to devices of a certain manufacturer') ) napalm_driver = models.CharField( max_length=50, blank=True, verbose_name='NAPALM driver', - help_text='The name of the NAPALM driver to use when interacting with devices' + help_text=_('The name of the NAPALM driver to use when interacting with devices') ) napalm_args = models.JSONField( blank=True, null=True, verbose_name='NAPALM arguments', - help_text='Additional arguments to pass when initiating the NAPALM driver (JSON format)' + help_text=_('Additional arguments to pass when initiating the NAPALM driver (JSON format)') ) def get_absolute_url(self): @@ -496,7 +497,7 @@ class Device(PrimaryModel, ConfigContextModel): null=True, unique=True, verbose_name='Asset tag', - help_text='A unique tag used to identify this device' + help_text=_('A unique tag used to identify this device') ) site = models.ForeignKey( to='dcim.Site', @@ -524,7 +525,7 @@ class Device(PrimaryModel, ConfigContextModel): null=True, validators=[MinValueValidator(1), MaxValueValidator(99.5)], verbose_name='Position (U)', - help_text='The lowest-numbered unit occupied by the device' + help_text=_('The lowest-numbered unit occupied by the device') ) face = models.CharField( max_length=50, @@ -929,7 +930,7 @@ class Module(PrimaryModel, ConfigContextModel): null=True, unique=True, verbose_name='Asset tag', - help_text='A unique tag used to identify this device' + help_text=_('A unique tag used to identify this device') ) clone_fields = ('device', 'module_type') diff --git a/netbox/dcim/models/power.py b/netbox/dcim/models/power.py index e79cf4c44..a910b1437 100644 --- a/netbox/dcim/models/power.py +++ b/netbox/dcim/models/power.py @@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.urls import reverse +from django.utils.translation import gettext as _ from dcim.choices import * from netbox.config import ConfigItem @@ -125,7 +126,7 @@ class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel): max_utilization = models.PositiveSmallIntegerField( validators=[MinValueValidator(1), MaxValueValidator(100)], default=ConfigItem('POWERFEED_DEFAULT_MAX_UTILIZATION'), - help_text="Maximum permissible draw (percentage)" + help_text=_("Maximum permissible draw (percentage)") ) available_power = models.PositiveIntegerField( default=0, diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index e37fc8dc3..ff37aff5a 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -10,6 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.db.models import Count from django.urls import reverse +from django.utils.translation import gettext as _ from dcim.choices import * from dcim.constants import * @@ -64,7 +65,7 @@ class Rack(PrimaryModel, WeightMixin): blank=True, null=True, verbose_name='Facility ID', - help_text='Locally-assigned identifier' + help_text=_('Locally-assigned identifier') ) site = models.ForeignKey( to='dcim.Site', @@ -96,7 +97,7 @@ class Rack(PrimaryModel, WeightMixin): related_name='racks', blank=True, null=True, - help_text='Functional role' + help_text=_('Functional role') ) serial = models.CharField( max_length=50, @@ -109,7 +110,7 @@ class Rack(PrimaryModel, WeightMixin): null=True, unique=True, verbose_name='Asset tag', - help_text='A unique tag used to identify this rack' + help_text=_('A unique tag used to identify this rack') ) type = models.CharField( choices=RackTypeChoices, @@ -121,28 +122,28 @@ class Rack(PrimaryModel, WeightMixin): choices=RackWidthChoices, default=RackWidthChoices.WIDTH_19IN, verbose_name='Width', - help_text='Rail-to-rail width' + help_text=_('Rail-to-rail width') ) u_height = models.PositiveSmallIntegerField( default=RACK_U_HEIGHT_DEFAULT, verbose_name='Height (U)', validators=[MinValueValidator(1), MaxValueValidator(100)], - help_text='Height in rack units' + help_text=_('Height in rack units') ) desc_units = models.BooleanField( default=False, verbose_name='Descending units', - help_text='Units are numbered top-to-bottom' + help_text=_('Units are numbered top-to-bottom') ) outer_width = models.PositiveSmallIntegerField( blank=True, null=True, - help_text='Outer dimension of rack (width)' + help_text=_('Outer dimension of rack (width)') ) outer_depth = models.PositiveSmallIntegerField( blank=True, null=True, - help_text='Outer dimension of rack (depth)' + help_text=_('Outer dimension of rack (depth)') ) outer_unit = models.CharField( max_length=50, @@ -153,8 +154,8 @@ class Rack(PrimaryModel, WeightMixin): blank=True, null=True, help_text=( - 'Maximum depth of a mounted device, in millimeters. For four-post racks, this is the ' - 'distance between the front and rear rails.' + _('Maximum depth of a mounted device, in millimeters. For four-post racks, this is the ' + 'distance between the front and rear rails.') ) ) diff --git a/netbox/dcim/models/sites.py b/netbox/dcim/models/sites.py index c760119fb..33f695e70 100644 --- a/netbox/dcim/models/sites.py +++ b/netbox/dcim/models/sites.py @@ -2,6 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse +from django.utils.translation import gettext as _ from timezone_field import TimeZoneField from dcim.choices import * @@ -178,7 +179,7 @@ class Site(PrimaryModel): facility = models.CharField( max_length=50, blank=True, - help_text='Local facility ID or description' + help_text=_('Local facility ID or description') ) asns = models.ManyToManyField( to='ipam.ASN', @@ -201,14 +202,14 @@ class Site(PrimaryModel): decimal_places=6, blank=True, null=True, - help_text='GPS coordinate (latitude)' + help_text=_('GPS coordinate (latitude)') ) longitude = models.DecimalField( max_digits=9, decimal_places=6, blank=True, null=True, - help_text='GPS coordinate (longitude)' + help_text=_('GPS coordinate (longitude)') ) # Generic relations diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index 6010c733a..824ba90cb 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -2,6 +2,7 @@ import django_filters from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType from django.db.models import Q +from django.utils.translation import gettext as _ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet @@ -32,7 +33,7 @@ __all__ = ( class WebhookFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) content_type_id = MultiValueNumberFilter( field_name='content_types__id' @@ -61,7 +62,7 @@ class WebhookFilterSet(BaseFilterSet): class CustomFieldFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) type = django_filters.MultipleChoiceFilter( choices=CustomFieldTypeChoices @@ -92,7 +93,7 @@ class CustomFieldFilterSet(BaseFilterSet): class CustomLinkFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) content_type_id = MultiValueNumberFilter( field_name='content_types__id' @@ -119,7 +120,7 @@ class CustomLinkFilterSet(BaseFilterSet): class ExportTemplateFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) content_type_id = MultiValueNumberFilter( field_name='content_types__id' @@ -142,7 +143,7 @@ class ExportTemplateFilterSet(BaseFilterSet): class SavedFilterFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) content_type_id = MultiValueNumberFilter( field_name='content_types__id' @@ -150,13 +151,13 @@ class SavedFilterFilterSet(BaseFilterSet): content_types = ContentTypeFilter() user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), - label='User (ID)', + label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), to_field_name='username', - label='User (name)', + label=_('User (name)'), ) usable = django_filters.BooleanFilter( method='_usable' @@ -191,7 +192,7 @@ class SavedFilterFilterSet(BaseFilterSet): class ImageAttachmentFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) created = django_filters.DateTimeFilter() content_type = ContentTypeFilter() @@ -211,13 +212,13 @@ class JournalEntryFilterSet(NetBoxModelFilterSet): assigned_object_type = ContentTypeFilter() created_by_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), - label='User (ID)', + label=_('User (ID)'), ) created_by = django_filters.ModelMultipleChoiceFilter( field_name='created_by__username', queryset=User.objects.all(), to_field_name='username', - label='User (name)', + label=_('User (name)'), ) kind = django_filters.MultipleChoiceFilter( choices=JournalEntryKindChoices @@ -236,7 +237,7 @@ class JournalEntryFilterSet(NetBoxModelFilterSet): class TagFilterSet(ChangeLoggedModelFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) content_type = MultiValueCharFilter( method='_content_type' @@ -288,138 +289,138 @@ class TagFilterSet(ChangeLoggedModelFilterSet): class ConfigContextFilterSet(ChangeLoggedModelFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) region_id = django_filters.ModelMultipleChoiceFilter( field_name='regions', queryset=Region.objects.all(), - label='Region', + label=_('Region'), ) region = django_filters.ModelMultipleChoiceFilter( field_name='regions__slug', queryset=Region.objects.all(), to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group = django_filters.ModelMultipleChoiceFilter( field_name='site_groups__slug', queryset=SiteGroup.objects.all(), to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_group_id = django_filters.ModelMultipleChoiceFilter( field_name='site_groups', queryset=SiteGroup.objects.all(), - label='Site group', + label=_('Site group'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='sites', queryset=Site.objects.all(), - label='Site', + label=_('Site'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='sites__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) location_id = django_filters.ModelMultipleChoiceFilter( field_name='locations', queryset=Location.objects.all(), - label='Location', + label=_('Location'), ) location = django_filters.ModelMultipleChoiceFilter( field_name='locations__slug', queryset=Location.objects.all(), to_field_name='slug', - label='Location (slug)', + label=_('Location (slug)'), ) device_type_id = django_filters.ModelMultipleChoiceFilter( field_name='device_types', queryset=DeviceType.objects.all(), - label='Device type', + label=_('Device type'), ) role_id = django_filters.ModelMultipleChoiceFilter( field_name='roles', queryset=DeviceRole.objects.all(), - label='Role', + label=_('Role'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='roles__slug', queryset=DeviceRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) platform_id = django_filters.ModelMultipleChoiceFilter( field_name='platforms', queryset=Platform.objects.all(), - label='Platform', + label=_('Platform'), ) platform = django_filters.ModelMultipleChoiceFilter( field_name='platforms__slug', queryset=Platform.objects.all(), to_field_name='slug', - label='Platform (slug)', + label=_('Platform (slug)'), ) cluster_type_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster_types', queryset=ClusterType.objects.all(), - label='Cluster type', + label=_('Cluster type'), ) cluster_type = django_filters.ModelMultipleChoiceFilter( field_name='cluster_types__slug', queryset=ClusterType.objects.all(), to_field_name='slug', - label='Cluster type (slug)', + label=_('Cluster type (slug)'), ) cluster_group_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster_groups', queryset=ClusterGroup.objects.all(), - label='Cluster group', + label=_('Cluster group'), ) cluster_group = django_filters.ModelMultipleChoiceFilter( field_name='cluster_groups__slug', queryset=ClusterGroup.objects.all(), to_field_name='slug', - label='Cluster group (slug)', + label=_('Cluster group (slug)'), ) cluster_id = django_filters.ModelMultipleChoiceFilter( field_name='clusters', queryset=Cluster.objects.all(), - label='Cluster', + label=_('Cluster'), ) tenant_group_id = django_filters.ModelMultipleChoiceFilter( field_name='tenant_groups', queryset=TenantGroup.objects.all(), - label='Tenant group', + label=_('Tenant group'), ) tenant_group = django_filters.ModelMultipleChoiceFilter( field_name='tenant_groups__slug', queryset=TenantGroup.objects.all(), to_field_name='slug', - label='Tenant group (slug)', + label=_('Tenant group (slug)'), ) tenant_id = django_filters.ModelMultipleChoiceFilter( field_name='tenants', queryset=Tenant.objects.all(), - label='Tenant', + label=_('Tenant'), ) tenant = django_filters.ModelMultipleChoiceFilter( field_name='tenants__slug', queryset=Tenant.objects.all(), to_field_name='slug', - label='Tenant (slug)', + label=_('Tenant (slug)'), ) tag_id = django_filters.ModelMultipleChoiceFilter( field_name='tags', queryset=Tag.objects.all(), - label='Tag', + label=_('Tag'), ) tag = django_filters.ModelMultipleChoiceFilter( field_name='tags__slug', queryset=Tag.objects.all(), to_field_name='slug', - label='Tag (slug)', + label=_('Tag (slug)'), ) class Meta: @@ -443,7 +444,7 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet): class LocalConfigContextFilterSet(django_filters.FilterSet): local_context_data = django_filters.BooleanFilter( method='_local_context_data', - label='Has local config context data', + label=_('Has local config context data'), ) def _local_context_data(self, queryset, name, value): @@ -453,19 +454,19 @@ class LocalConfigContextFilterSet(django_filters.FilterSet): class ObjectChangeFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) time = django_filters.DateTimeFromToRangeFilter() changed_object_type = ContentTypeFilter() user_id = django_filters.ModelMultipleChoiceFilter( queryset=User.objects.all(), - label='User (ID)', + label=_('User (ID)'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), to_field_name='username', - label='User name', + label=_('User name'), ) class Meta: @@ -491,7 +492,7 @@ class ObjectChangeFilterSet(BaseFilterSet): class JobResultFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) created = django_filters.DateTimeFilter() created__before = django_filters.DateTimeFilter( @@ -547,7 +548,7 @@ class JobResultFilterSet(BaseFilterSet): class ContentTypeFilterSet(django_filters.FilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) class Meta: diff --git a/netbox/extras/forms/bulk_edit.py b/netbox/extras/forms/bulk_edit.py index a061d9784..6e245bcaf 100644 --- a/netbox/extras/forms/bulk_edit.py +++ b/netbox/extras/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from extras.choices import * from extras.models import * @@ -37,7 +38,7 @@ class CustomFieldBulkEditForm(BulkEditForm): required=False ) ui_visibility = forms.ChoiceField( - label="UI visibility", + label=_("UI visibility"), choices=add_blank_choice(CustomFieldVisibilityChoices), required=False, initial='', @@ -143,23 +144,23 @@ class WebhookBulkEditForm(BulkEditForm): http_method = forms.ChoiceField( choices=add_blank_choice(WebhookHttpMethodChoices), required=False, - label='HTTP method' + label=_('HTTP method') ) payload_url = forms.CharField( required=False, - label='Payload URL' + label=_('Payload URL') ) ssl_verification = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), - label='SSL verification' + label=_('SSL verification') ) secret = forms.CharField( required=False ) ca_file_path = forms.CharField( required=False, - label='CA file path' + label=_('CA file path') ) nullable_fields = ('secret', 'conditions', 'ca_file_path') diff --git a/netbox/extras/forms/bulk_import.py b/netbox/extras/forms/bulk_import.py index 0f5974698..9def8fda6 100644 --- a/netbox/extras/forms/bulk_import.py +++ b/netbox/extras/forms/bulk_import.py @@ -2,6 +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 extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices from extras.models import * @@ -22,26 +23,26 @@ class CustomFieldCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), - help_text="One or more assigned object types" + help_text=_("One or more assigned object types") ) type = CSVChoiceField( choices=CustomFieldTypeChoices, - help_text='Field data type (e.g. text, integer, etc.)' + help_text=_('Field data type (e.g. text, integer, etc.)') ) object_type = CSVContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False, - help_text="Object type (for object or multi-object fields)" + help_text=_("Object type (for object or multi-object fields)") ) choices = SimpleArrayField( base_field=forms.CharField(), required=False, - help_text='Comma-separated list of field choices' + help_text=_('Comma-separated list of field choices') ) ui_visibility = CSVChoiceField( choices=CustomFieldVisibilityChoices, - help_text='How the custom field is displayed in the user interface' + help_text=_('How the custom field is displayed in the user interface') ) class Meta: @@ -57,7 +58,7 @@ class CustomLinkCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), - help_text="One or more assigned object types" + help_text=_("One or more assigned object types") ) class Meta: @@ -72,7 +73,7 @@ class ExportTemplateCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), - help_text="One or more assigned object types" + help_text=_("One or more assigned object types") ) class Meta: @@ -85,7 +86,7 @@ class ExportTemplateCSVForm(CSVModelForm): class SavedFilterCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), - help_text="One or more assigned object types" + help_text=_("One or more assigned object types") ) class Meta: @@ -99,7 +100,7 @@ class WebhookCSVForm(CSVModelForm): content_types = CSVMultipleContentTypeField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), - help_text="One or more assigned object types" + help_text=_("One or more assigned object types") ) class Meta: @@ -118,5 +119,5 @@ class TagCSVForm(CSVModelForm): model = Tag fields = ('name', 'slug', 'color', 'description') help_texts = { - 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), + 'color': mark_safe(_('RGB color in hexadecimal (e.g. 00ff00)')), } diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 479367ff0..0421cab22 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -41,7 +41,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False, - label='Object type' + label=_('Object type') ) type = MultipleChoiceField( choices=CustomFieldTypeChoices, @@ -209,7 +209,7 @@ class WebhookFilterForm(SavedFiltersMixin, FilterForm): queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), required=False, - label='Object type' + label=_('Object type') ) http_method = MultipleChoiceField( choices=WebhookHttpMethodChoices, diff --git a/netbox/extras/forms/mixins.py b/netbox/extras/forms/mixins.py index 2b64d1a74..0a7dbdbcf 100644 --- a/netbox/extras/forms/mixins.py +++ b/netbox/extras/forms/mixins.py @@ -1,5 +1,6 @@ from django.contrib.contenttypes.models import ContentType from django import forms +from django.utils.translation import gettext as _ from extras.models import * from extras.choices import CustomFieldVisibilityChoices @@ -66,7 +67,7 @@ class SavedFiltersMixin(forms.Form): filter = DynamicModelMultipleChoiceField( queryset=SavedFilter.objects.all(), required=False, - label='Saved Filter', + label=_('Saved Filter'), query_params={ 'usable': True, } diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 97e80100a..192cdeeec 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -1,6 +1,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.http import QueryDict +from django.utils.translation import gettext as _ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from extras.choices import * @@ -31,14 +32,14 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), - label='Model(s)' + label=_('Model(s)') ) object_type = ContentTypeChoiceField( queryset=ContentType.objects.all(), # TODO: Come up with a canonical way to register suitable models limit_choices_to=FeatureQuery('webhooks'), required=False, - help_text="Type of the related object (for object/multi-object fields only)" + help_text=_("Type of the related object (for object/multi-object fields only)") ) fieldsets = ( @@ -54,8 +55,8 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm): model = CustomField fields = '__all__' help_texts = { - 'type': "The type of data stored in this field. For object/multi-object fields, select the related object " - "type below." + 'type': _("The type of data stored in this field. For object/multi-object fields, select the related object " + "type below.") } widgets = { 'type': StaticSelect(), @@ -84,9 +85,9 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm): 'link_url': forms.Textarea(attrs={'class': 'font-monospace'}), } help_texts = { - 'link_text': 'Jinja2 template code for the link text. Reference the object as {{ object }}. ' - 'Links which render as empty text will not be displayed.', - 'link_url': 'Jinja2 template code for the link URL. Reference the object as {{ object }}.', + 'link_text': _('Jinja2 template code for the link text. Reference the object as {{ object }}. ' + 'Links which render as empty text will not be displayed.'), + 'link_url': _('Jinja2 template code for the link URL. Reference the object as {{ object }}.'), } diff --git a/netbox/extras/forms/reports.py b/netbox/extras/forms/reports.py index aa4f6223b..863cf29c1 100644 --- a/netbox/extras/forms/reports.py +++ b/netbox/extras/forms/reports.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from utilities.forms import BootstrapMixin, DateTimePicker @@ -11,6 +12,6 @@ class ReportForm(BootstrapMixin, forms.Form): schedule_at = forms.DateTimeField( required=False, widget=DateTimePicker(), - label="Schedule at", - help_text="Schedule execution of report to a set time", + label=_("Schedule at"), + help_text=_("Schedule execution of report to a set time"), ) diff --git a/netbox/extras/forms/scripts.py b/netbox/extras/forms/scripts.py index de55a3ee6..74c865c8d 100644 --- a/netbox/extras/forms/scripts.py +++ b/netbox/extras/forms/scripts.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from utilities.forms import BootstrapMixin, DateTimePicker @@ -11,14 +12,14 @@ class ScriptForm(BootstrapMixin, forms.Form): _commit = forms.BooleanField( required=False, initial=True, - label="Commit changes", - help_text="Commit changes to the database (uncheck for a dry-run)" + label=_("Commit changes"), + help_text=_("Commit changes to the database (uncheck for a dry-run)") ) _schedule_at = forms.DateTimeField( required=False, widget=DateTimePicker(), - label="Schedule at", - help_text="Schedule execution of script to a set time", + label=_("Schedule at"), + help_text=_("Schedule execution of script to a set time"), ) def __init__(self, *args, **kwargs): diff --git a/netbox/extras/models/customfields.py b/netbox/extras/models/customfields.py index 2de806ca6..b03149698 100644 --- a/netbox/extras/models/customfields.py +++ b/netbox/extras/models/customfields.py @@ -11,6 +11,7 @@ from django.db import models from django.urls import reverse from django.utils.html import escape from django.utils.safestring import mark_safe +from django.utils.translation import gettext as _ from extras.choices import * from extras.utils import FeatureQuery @@ -57,25 +58,25 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge to=ContentType, related_name='custom_fields', limit_choices_to=FeatureQuery('custom_fields'), - help_text='The object(s) to which this field applies.' + help_text=_('The object(s) to which this field applies.') ) type = models.CharField( max_length=50, choices=CustomFieldTypeChoices, default=CustomFieldTypeChoices.TYPE_TEXT, - help_text='The type of data this custom field holds' + help_text=_('The type of data this custom field holds') ) object_type = models.ForeignKey( to=ContentType, on_delete=models.PROTECT, blank=True, null=True, - help_text='The type of NetBox object this field maps to (for object fields)' + help_text=_('The type of NetBox object this field maps to (for object fields)') ) name = models.CharField( max_length=50, unique=True, - help_text='Internal field name', + help_text=_('Internal field name'), validators=( RegexValidator( regex=r'^[a-z0-9_]+$', @@ -87,13 +88,13 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge label = models.CharField( max_length=50, blank=True, - help_text='Name of the field as displayed to users (if not provided, ' - 'the field\'s name will be used)' + help_text=_('Name of the field as displayed to users (if not provided, ' + 'the field\'s name will be used)') ) group_name = models.CharField( max_length=50, blank=True, - help_text="Custom fields within the same group will be displayed together" + help_text=_("Custom fields within the same group will be displayed together") ) description = models.CharField( max_length=200, @@ -101,64 +102,64 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge ) required = models.BooleanField( default=False, - help_text='If true, this field is required when creating new objects ' - 'or editing an existing object.' + help_text=_('If true, this field is required when creating new objects ' + 'or editing an existing object.') ) search_weight = models.PositiveSmallIntegerField( default=1000, - help_text='Weighting for search. Lower values are considered more important. ' - 'Fields with a search weight of zero will be ignored.' + help_text=_('Weighting for search. Lower values are considered more important. ' + 'Fields with a search weight of zero will be ignored.') ) filter_logic = models.CharField( max_length=50, choices=CustomFieldFilterLogicChoices, default=CustomFieldFilterLogicChoices.FILTER_LOOSE, - help_text='Loose matches any instance of a given string; exact ' - 'matches the entire field.' + help_text=_('Loose matches any instance of a given string; exact ' + 'matches the entire field.') ) default = models.JSONField( blank=True, null=True, - help_text='Default value for the field (must be a JSON value). Encapsulate ' - 'strings with double quotes (e.g. "Foo").' + help_text=_('Default value for the field (must be a JSON value). Encapsulate ' + 'strings with double quotes (e.g. "Foo").') ) weight = models.PositiveSmallIntegerField( default=100, verbose_name='Display weight', - help_text='Fields with higher weights appear lower in a form.' + help_text=_('Fields with higher weights appear lower in a form.') ) validation_minimum = models.IntegerField( blank=True, null=True, verbose_name='Minimum value', - help_text='Minimum allowed value (for numeric fields)' + help_text=_('Minimum allowed value (for numeric fields)') ) validation_maximum = models.IntegerField( blank=True, null=True, verbose_name='Maximum value', - help_text='Maximum allowed value (for numeric fields)' + help_text=_('Maximum allowed value (for numeric fields)') ) validation_regex = models.CharField( blank=True, validators=[validate_regex], max_length=500, verbose_name='Validation regex', - help_text='Regular expression to enforce on text field values. Use ^ and $ to force matching of entire string. ' - 'For example, ^[A-Z]{3}$ will limit values to exactly three uppercase letters.' + help_text=_('Regular expression to enforce on text field values. Use ^ and $ to force matching of entire string. ' + 'For example, ^[A-Z]{3}$ will limit values to exactly three uppercase letters.') ) choices = ArrayField( base_field=models.CharField(max_length=100), blank=True, null=True, - help_text='Comma-separated list of available choices (for selection fields)' + help_text=_('Comma-separated list of available choices (for selection fields)') ) ui_visibility = models.CharField( max_length=50, choices=CustomFieldVisibilityChoices, default=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE, verbose_name='UI visibility', - help_text='Specifies the visibility of custom field in the UI' + help_text=_('Specifies the visibility of custom field in the UI') ) objects = CustomFieldManager() diff --git a/netbox/extras/models/models.py b/netbox/extras/models/models.py index 4b4e7c0cf..c33245f99 100644 --- a/netbox/extras/models/models.py +++ b/netbox/extras/models/models.py @@ -12,6 +12,7 @@ from django.http import HttpResponse, QueryDict from django.urls import reverse from django.utils import timezone from django.utils.formats import date_format +from django.utils.translation import gettext as _ from rest_framework.utils.encoders import JSONEncoder import django_rq @@ -51,7 +52,7 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): related_name='webhooks', verbose_name='Object types', limit_choices_to=FeatureQuery('webhooks'), - help_text="The object(s) to which this Webhook applies." + help_text=_("The object(s) to which this Webhook applies.") ) name = models.CharField( max_length=150, @@ -59,21 +60,21 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): ) type_create = models.BooleanField( default=False, - help_text="Call this webhook when a matching object is created." + help_text=_("Call this webhook when a matching object is created.") ) type_update = models.BooleanField( default=False, - help_text="Call this webhook when a matching object is updated." + help_text=_("Call this webhook when a matching object is updated.") ) type_delete = models.BooleanField( default=False, - help_text="Call this webhook when a matching object is deleted." + help_text=_("Call this webhook when a matching object is deleted.") ) payload_url = models.CharField( max_length=500, verbose_name='URL', - help_text='This URL will be called using the HTTP method defined when the webhook is called. ' - 'Jinja2 template processing is supported with the same context as the request body.' + help_text=_('This URL will be called using the HTTP method defined when the webhook is called. ' + 'Jinja2 template processing is supported with the same context as the request body.') ) enabled = models.BooleanField( default=True @@ -88,46 +89,46 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): max_length=100, default=HTTP_CONTENT_TYPE_JSON, verbose_name='HTTP content type', - help_text='The complete list of official content types is available ' - 'here.' + help_text=_('The complete list of official content types is available ' + 'here.') ) additional_headers = models.TextField( blank=True, - help_text="User-supplied HTTP headers to be sent with the request in addition to the HTTP content type. " - "Headers should be defined in the format Name: Value. Jinja2 template processing is " - "supported with the same context as the request body (below)." + help_text=_("User-supplied HTTP headers to be sent with the request in addition to the HTTP content type. " + "Headers should be defined in the format Name: Value. Jinja2 template processing is " + "supported with the same context as the request body (below).") ) body_template = models.TextField( blank=True, - help_text='Jinja2 template for a custom request body. If blank, a JSON object representing the change will be ' - 'included. Available context data includes: event, model, ' - 'timestamp, username, request_id, and data.' + help_text=_('Jinja2 template for a custom request body. If blank, a JSON object representing the change will be ' + 'included. Available context data includes: event, model, ' + 'timestamp, username, request_id, and data.') ) secret = models.CharField( max_length=255, blank=True, - help_text="When provided, the request will include a 'X-Hook-Signature' " - "header containing a HMAC hex digest of the payload body using " - "the secret as the key. The secret is not transmitted in " - "the request." + help_text=_("When provided, the request will include a 'X-Hook-Signature' " + "header containing a HMAC hex digest of the payload body using " + "the secret as the key. The secret is not transmitted in " + "the request.") ) conditions = models.JSONField( blank=True, null=True, - help_text="A set of conditions which determine whether the webhook will be generated." + help_text=_("A set of conditions which determine whether the webhook will be generated.") ) ssl_verification = models.BooleanField( default=True, verbose_name='SSL verification', - help_text="Enable SSL certificate verification. Disable with caution!" + help_text=_("Enable SSL certificate verification. Disable with caution!") ) ca_file_path = models.CharField( max_length=4096, null=True, blank=True, verbose_name='CA File Path', - help_text='The specific CA certificate file to use for SSL verification. ' - 'Leave blank to use the system defaults.' + help_text=_('The specific CA certificate file to use for SSL verification. ' + 'Leave blank to use the system defaults.') ) class Meta: @@ -201,7 +202,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged content_types = models.ManyToManyField( to=ContentType, related_name='custom_links', - help_text='The object type(s) to which this link applies.' + help_text=_('The object type(s) to which this link applies.') ) name = models.CharField( max_length=100, @@ -211,11 +212,11 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged default=True ) link_text = models.TextField( - help_text="Jinja2 template code for link text" + help_text=_("Jinja2 template code for link text") ) link_url = models.TextField( verbose_name='Link URL', - help_text="Jinja2 template code for link URL" + help_text=_("Jinja2 template code for link URL") ) weight = models.PositiveSmallIntegerField( default=100 @@ -223,17 +224,17 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged group_name = models.CharField( max_length=50, blank=True, - help_text="Links with the same group will appear as a dropdown menu" + help_text=_("Links with the same group will appear as a dropdown menu") ) button_class = models.CharField( max_length=30, choices=CustomLinkButtonClassChoices, default=CustomLinkButtonClassChoices.DEFAULT, - help_text="The class of the first link in a group will be used for the dropdown button" + help_text=_("The class of the first link in a group will be used for the dropdown button") ) new_window = models.BooleanField( default=False, - help_text="Force link to open in a new window" + help_text=_("Force link to open in a new window") ) clone_fields = ( @@ -272,7 +273,7 @@ class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): content_types = models.ManyToManyField( to=ContentType, related_name='export_templates', - help_text='The object type(s) to which this template applies.' + help_text=_('The object type(s) to which this template applies.') ) name = models.CharField( max_length=100 @@ -282,23 +283,23 @@ class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel): blank=True ) template_code = models.TextField( - help_text='Jinja2 template code. The list of objects being exported is passed as a context variable named ' - 'queryset.' + help_text=_('Jinja2 template code. The list of objects being exported is passed as a context variable named ' + 'queryset.') ) mime_type = models.CharField( max_length=50, blank=True, verbose_name='MIME type', - help_text='Defaults to text/plain' + help_text=_('Defaults to text/plain') ) file_extension = models.CharField( max_length=15, blank=True, - help_text='Extension to append to the rendered filename' + help_text=_('Extension to append to the rendered filename') ) as_attachment = models.BooleanField( default=True, - help_text="Download file as attachment" + help_text=_("Download file as attachment") ) class Meta: @@ -358,7 +359,7 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge content_types = models.ManyToManyField( to=ContentType, related_name='saved_filters', - help_text='The object type(s) to which this filter applies.' + help_text=_('The object type(s) to which this filter applies.') ) name = models.CharField( max_length=100, @@ -553,7 +554,7 @@ class JobResult(models.Model): related_name='job_results', verbose_name='Object types', limit_choices_to=FeatureQuery('job_results'), - help_text="The object type to which this job result applies", + help_text=_("The object type to which this job result applies"), on_delete=models.CASCADE, ) created = models.DateTimeField( diff --git a/netbox/extras/tests/dummy_plugin/navigation.py b/netbox/extras/tests/dummy_plugin/navigation.py index a475b1cde..8aa161520 100644 --- a/netbox/extras/tests/dummy_plugin/navigation.py +++ b/netbox/extras/tests/dummy_plugin/navigation.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem @@ -25,7 +26,7 @@ items = ( ) menu = PluginMenu( - label='Dummy', + label=_('Dummy'), groups=(('Group 1', items),), ) menu_items = items diff --git a/netbox/ipam/filtersets.py b/netbox/ipam/filtersets.py index 360cf2a56..b5478b7a0 100644 --- a/netbox/ipam/filtersets.py +++ b/netbox/ipam/filtersets.py @@ -3,6 +3,7 @@ import netaddr 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 netaddr.core import AddrFormatError from dcim.models import Device, Interface, Region, Site, SiteGroup @@ -41,24 +42,24 @@ class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet): import_target_id = django_filters.ModelMultipleChoiceFilter( field_name='import_targets', queryset=RouteTarget.objects.all(), - label='Import target', + label=_('Import target'), ) import_target = django_filters.ModelMultipleChoiceFilter( field_name='import_targets__name', queryset=RouteTarget.objects.all(), to_field_name='name', - label='Import target (name)', + label=_('Import target (name)'), ) export_target_id = django_filters.ModelMultipleChoiceFilter( field_name='export_targets', queryset=RouteTarget.objects.all(), - label='Export target', + label=_('Export target'), ) export_target = django_filters.ModelMultipleChoiceFilter( field_name='export_targets__name', queryset=RouteTarget.objects.all(), to_field_name='name', - label='Export target (name)', + label=_('Export target (name)'), ) def search(self, queryset, name, value): @@ -79,24 +80,24 @@ class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet): importing_vrf_id = django_filters.ModelMultipleChoiceFilter( field_name='importing_vrfs', queryset=VRF.objects.all(), - label='Importing VRF', + label=_('Importing VRF'), ) importing_vrf = django_filters.ModelMultipleChoiceFilter( field_name='importing_vrfs__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='Import VRF (RD)', + label=_('Import VRF (RD)'), ) exporting_vrf_id = django_filters.ModelMultipleChoiceFilter( field_name='exporting_vrfs', queryset=VRF.objects.all(), - label='Exporting VRF', + label=_('Exporting VRF'), ) exporting_vrf = django_filters.ModelMultipleChoiceFilter( field_name='exporting_vrfs__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='Export VRF (RD)', + label=_('Export VRF (RD)'), ) def search(self, queryset, name, value): @@ -126,17 +127,17 @@ class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet): ) prefix = django_filters.CharFilter( method='filter_prefix', - label='Prefix', + label=_('Prefix'), ) rir_id = django_filters.ModelMultipleChoiceFilter( queryset=RIR.objects.all(), - label='RIR (ID)', + label=_('RIR (ID)'), ) rir = django_filters.ModelMultipleChoiceFilter( field_name='rir__slug', queryset=RIR.objects.all(), to_field_name='slug', - label='RIR (slug)', + label=_('RIR (slug)'), ) class Meta: @@ -169,24 +170,24 @@ class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): rir_id = django_filters.ModelMultipleChoiceFilter( queryset=RIR.objects.all(), - label='RIR (ID)', + label=_('RIR (ID)'), ) rir = django_filters.ModelMultipleChoiceFilter( field_name='rir__slug', queryset=RIR.objects.all(), to_field_name='slug', - label='RIR (slug)', + label=_('RIR (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( field_name='sites', queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='sites__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) class Meta: @@ -218,19 +219,19 @@ class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet): ) prefix = MultiValueCharFilter( method='filter_prefix', - label='Prefix', + label=_('Prefix'), ) within = django_filters.CharFilter( method='search_within', - label='Within prefix', + label=_('Within prefix'), ) within_include = django_filters.CharFilter( method='search_within_include', - label='Within and including prefix', + label=_('Within and including prefix'), ) contains = django_filters.CharFilter( method='search_contains', - label='Prefixes which contain this prefix or IP', + label=_('Prefixes which contain this prefix or IP'), ) depth = MultiValueNumberFilter( field_name='_depth' @@ -252,78 +253,78 @@ class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet): ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), - label='VRF', + label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) present_in_vrf_id = django_filters.ModelChoiceFilter( queryset=VRF.objects.all(), method='filter_present_in_vrf', - label='VRF' + label=_('VRF') ) present_in_vrf = django_filters.ModelChoiceFilter( queryset=VRF.objects.all(), method='filter_present_in_vrf', to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) vlan_id = django_filters.ModelMultipleChoiceFilter( queryset=VLAN.objects.all(), - label='VLAN (ID)', + label=_('VLAN (ID)'), ) vlan_vid = django_filters.NumberFilter( field_name='vlan__vid', - label='VLAN number (1-4094)', + label=_('VLAN number (1-4094)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=PrefixStatusChoices, @@ -406,27 +407,27 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet): ) contains = django_filters.CharFilter( method='search_contains', - label='Ranges which contain this prefix or IP', + label=_('Ranges which contain this prefix or IP'), ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), - label='VRF', + label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=IPRangeStatusChoices, @@ -468,87 +469,87 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet): ) parent = MultiValueCharFilter( method='search_by_parent', - label='Parent prefix', + label=_('Parent prefix'), ) address = MultiValueCharFilter( method='filter_address', - label='Address', + label=_('Address'), ) mask_length = django_filters.NumberFilter( method='filter_mask_length', - label='Mask length', + label=_('Mask length'), ) vrf_id = django_filters.ModelMultipleChoiceFilter( queryset=VRF.objects.all(), - label='VRF', + label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) present_in_vrf_id = django_filters.ModelChoiceFilter( queryset=VRF.objects.all(), method='filter_present_in_vrf', - label='VRF' + label=_('VRF') ) present_in_vrf = django_filters.ModelChoiceFilter( queryset=VRF.objects.all(), method='filter_present_in_vrf', to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) device = MultiValueCharFilter( method='filter_device', field_name='name', - label='Device (name)', + label=_('Device (name)'), ) device_id = MultiValueNumberFilter( method='filter_device', field_name='pk', - label='Device (ID)', + label=_('Device (ID)'), ) virtual_machine = MultiValueCharFilter( method='filter_virtual_machine', field_name='name', - label='Virtual machine (name)', + label=_('Virtual machine (name)'), ) virtual_machine_id = MultiValueNumberFilter( method='filter_virtual_machine', field_name='pk', - label='Virtual machine (ID)', + label=_('Virtual machine (ID)'), ) interface = django_filters.ModelMultipleChoiceFilter( field_name='interface__name', queryset=Interface.objects.all(), to_field_name='name', - label='Interface (name)', + label=_('Interface (name)'), ) interface_id = django_filters.ModelMultipleChoiceFilter( field_name='interface', queryset=Interface.objects.all(), - label='Interface (ID)', + label=_('Interface (ID)'), ) vminterface = django_filters.ModelMultipleChoiceFilter( field_name='vminterface__name', queryset=VMInterface.objects.all(), to_field_name='name', - label='VM interface (name)', + label=_('VM interface (name)'), ) vminterface_id = django_filters.ModelMultipleChoiceFilter( field_name='vminterface', queryset=VMInterface.objects.all(), - label='VM interface (ID)', + label=_('VM interface (ID)'), ) fhrpgroup_id = django_filters.ModelMultipleChoiceFilter( field_name='fhrpgroup', queryset=FHRPGroup.objects.all(), - label='FHRP group (ID)', + label=_('FHRP group (ID)'), ) assigned_to_interface = django_filters.BooleanFilter( method='_assigned_to_interface', - label='Is assigned to an interface', + label=_('Is assigned to an interface'), ) status = django_filters.MultipleChoiceFilter( choices=IPAddressStatusChoices, @@ -688,27 +689,27 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet): interface_type = ContentTypeFilter() group_id = django_filters.ModelMultipleChoiceFilter( queryset=FHRPGroup.objects.all(), - label='Group (ID)', + label=_('Group (ID)'), ) device = MultiValueCharFilter( method='filter_device', field_name='name', - label='Device (name)', + label=_('Device (name)'), ) device_id = MultiValueNumberFilter( method='filter_device', field_name='pk', - label='Device (ID)', + label=_('Device (ID)'), ) virtual_machine = MultiValueCharFilter( method='filter_virtual_machine', field_name='name', - label='Virtual machine (name)', + label=_('Virtual machine (name)'), ) virtual_machine_id = MultiValueNumberFilter( method='filter_virtual_machine', field_name='pk', - label='Virtual machine (ID)', + label=_('Virtual machine (ID)'), ) class Meta: @@ -787,57 +788,57 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet): queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=VLANGroup.objects.all(), - label='Group (ID)', + label=_('Group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=VLANGroup.objects.all(), to_field_name='slug', - label='Group', + label=_('Group'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=Role.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=Role.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=VLANStatusChoices, @@ -893,23 +894,23 @@ class ServiceTemplateFilterSet(NetBoxModelFilterSet): class ServiceFilterSet(NetBoxModelFilterSet): device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), - label='Device (ID)', + label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), to_field_name='name', - label='Device (name)', + label=_('Device (name)'), ) virtual_machine_id = django_filters.ModelMultipleChoiceFilter( queryset=VirtualMachine.objects.all(), - label='Virtual machine (ID)', + label=_('Virtual machine (ID)'), ) virtual_machine = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__name', queryset=VirtualMachine.objects.all(), to_field_name='name', - label='Virtual machine (name)', + label=_('Virtual machine (name)'), ) port = NumericArrayFilter( field_name='ports', @@ -939,24 +940,24 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet): import_target_id = django_filters.ModelMultipleChoiceFilter( field_name='import_targets', queryset=RouteTarget.objects.all(), - label='Import target', + label=_('Import target'), ) import_target = django_filters.ModelMultipleChoiceFilter( field_name='import_targets__name', queryset=RouteTarget.objects.all(), to_field_name='name', - label='Import target (name)', + label=_('Import target (name)'), ) export_target_id = django_filters.ModelMultipleChoiceFilter( field_name='export_targets', queryset=RouteTarget.objects.all(), - label='Export target', + label=_('Export target'), ) export_target = django_filters.ModelMultipleChoiceFilter( field_name='export_targets__name', queryset=RouteTarget.objects.all(), to_field_name='name', - label='Export target (name)', + label=_('Export target (name)'), ) class Meta: @@ -977,92 +978,92 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class L2VPNTerminationFilterSet(NetBoxModelFilterSet): l2vpn_id = django_filters.ModelMultipleChoiceFilter( queryset=L2VPN.objects.all(), - label='L2VPN (ID)', + label=_('L2VPN (ID)'), ) l2vpn = django_filters.ModelMultipleChoiceFilter( field_name='l2vpn__slug', queryset=L2VPN.objects.all(), to_field_name='slug', - label='L2VPN (slug)', + label=_('L2VPN (slug)'), ) region = MultiValueCharFilter( method='filter_region', field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) region_id = MultiValueNumberFilter( method='filter_region', field_name='pk', - label='Region (ID)', + label=_('Region (ID)'), ) site = MultiValueCharFilter( method='filter_site', field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) site_id = MultiValueNumberFilter( method='filter_site', field_name='pk', - label='Site (ID)', + label=_('Site (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='interface__device__name', queryset=Device.objects.all(), to_field_name='name', - label='Device (name)', + label=_('Device (name)'), ) device_id = django_filters.ModelMultipleChoiceFilter( field_name='interface__device', queryset=Device.objects.all(), - label='Device (ID)', + label=_('Device (ID)'), ) virtual_machine = django_filters.ModelMultipleChoiceFilter( field_name='vminterface__virtual_machine__name', queryset=VirtualMachine.objects.all(), to_field_name='name', - label='Virtual machine (name)', + label=_('Virtual machine (name)'), ) virtual_machine_id = django_filters.ModelMultipleChoiceFilter( field_name='vminterface__virtual_machine', queryset=VirtualMachine.objects.all(), - label='Virtual machine (ID)', + label=_('Virtual machine (ID)'), ) interface = django_filters.ModelMultipleChoiceFilter( field_name='interface__name', queryset=Interface.objects.all(), to_field_name='name', - label='Interface (name)', + label=_('Interface (name)'), ) interface_id = django_filters.ModelMultipleChoiceFilter( field_name='interface', queryset=Interface.objects.all(), - label='Interface (ID)', + label=_('Interface (ID)'), ) vminterface = django_filters.ModelMultipleChoiceFilter( field_name='vminterface__name', queryset=VMInterface.objects.all(), to_field_name='name', - label='VM interface (name)', + label=_('VM interface (name)'), ) vminterface_id = django_filters.ModelMultipleChoiceFilter( field_name='vminterface', queryset=VMInterface.objects.all(), - label='VM Interface (ID)', + label=_('VM Interface (ID)'), ) vlan = django_filters.ModelMultipleChoiceFilter( field_name='vlan__name', queryset=VLAN.objects.all(), to_field_name='name', - label='VLAN (name)', + label=_('VLAN (name)'), ) vlan_vid = django_filters.NumberFilter( field_name='vlan__vid', - label='VLAN number (1-4094)', + label=_('VLAN number (1-4094)'), ) vlan_id = django_filters.ModelMultipleChoiceFilter( field_name='vlan', queryset=VLAN.objects.all(), - label='VLAN (ID)', + label=_('VLAN (ID)'), ) assigned_object_type = ContentTypeFilter() diff --git a/netbox/ipam/forms/bulk_create.py b/netbox/ipam/forms/bulk_create.py index 790474c6e..6d07951a3 100644 --- a/netbox/ipam/forms/bulk_create.py +++ b/netbox/ipam/forms/bulk_create.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from utilities.forms import BootstrapMixin, ExpandableIPAddressField @@ -9,5 +10,5 @@ __all__ = ( class IPAddressBulkCreateForm(BootstrapMixin, forms.Form): pattern = ExpandableIPAddressField( - label='Address pattern' + label=_('Address pattern') ) diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py index ed1d1d9e9..d0af43975 100644 --- a/netbox/ipam/forms/bulk_edit.py +++ b/netbox/ipam/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.models import Region, Site, SiteGroup from ipam.choices import * @@ -40,7 +41,7 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm): enforce_unique = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), - label='Enforce unique space' + label=_('Enforce unique space') ) description = forms.CharField( max_length=200, @@ -104,7 +105,7 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), required=False, - label='RIR' + label=_('RIR') ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -130,7 +131,7 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), required=False, - label='RIR' + label=_('RIR') ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -191,7 +192,7 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) prefix_length = forms.IntegerField( min_value=PREFIX_LENGTH_MIN, @@ -214,12 +215,12 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): is_pool = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), - label='Is a pool' + label=_('Is a pool') ) mark_utilized = forms.NullBooleanField( required=False, widget=BulkEditNullBooleanSelect(), - label='Treat as 100% utilized' + label=_('Treat as 100% utilized') ) description = forms.CharField( max_length=200, @@ -245,7 +246,7 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -282,7 +283,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) mask_length = forms.IntegerField( min_value=IPADDRESS_MASK_LENGTH_MIN, @@ -306,7 +307,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): dns_name = forms.CharField( max_length=255, required=False, - label='DNS name' + label=_('DNS name') ) description = forms.CharField( max_length=200, @@ -336,18 +337,18 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): group_id = forms.IntegerField( min_value=0, required=False, - label='Group ID' + label=_('Group ID') ) auth_type = forms.ChoiceField( choices=add_blank_choice(FHRPGroupAuthTypeChoices), required=False, widget=StaticSelect(), - label='Authentication type' + label=_('Authentication type') ) auth_key = forms.CharField( max_length=255, required=False, - label='Authentication key' + label=_('Authentication key') ) name = forms.CharField( max_length=100, @@ -379,13 +380,13 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, required=False, - label='Minimum child VLAN VID' + label=_('Minimum child VLAN VID') ) max_vid = forms.IntegerField( min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, required=False, - label='Maximum child VLAN VID' + label=_('Maximum child VLAN VID') ) description = forms.CharField( max_length=200, diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index 4cd0bb69f..177233717 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -1,6 +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 dcim.models import Device, Interface, Site from ipam.choices import * @@ -36,7 +37,7 @@ class VRFCSVForm(NetBoxModelCSVForm): queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -49,7 +50,7 @@ class RouteTargetCSVForm(NetBoxModelCSVForm): queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -64,7 +65,7 @@ class RIRCSVForm(NetBoxModelCSVForm): model = RIR fields = ('name', 'slug', 'is_private', 'description', 'tags') help_texts = { - 'name': 'RIR name', + 'name': _('RIR name'), } @@ -72,13 +73,13 @@ class AggregateCSVForm(NetBoxModelCSVForm): rir = CSVModelChoiceField( queryset=RIR.objects.all(), to_field_name='name', - help_text='Assigned RIR' + help_text=_('Assigned RIR') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -90,13 +91,13 @@ class ASNCSVForm(NetBoxModelCSVForm): rir = CSVModelChoiceField( queryset=RIR.objects.all(), to_field_name='name', - help_text='Assigned RIR' + help_text=_('Assigned RIR') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -117,41 +118,41 @@ class PrefixCSVForm(NetBoxModelCSVForm): queryset=VRF.objects.all(), to_field_name='name', required=False, - help_text='Assigned VRF' + help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) site = CSVModelChoiceField( queryset=Site.objects.all(), required=False, to_field_name='name', - help_text='Assigned site' + help_text=_('Assigned site') ) vlan_group = CSVModelChoiceField( queryset=VLANGroup.objects.all(), required=False, to_field_name='name', - help_text="VLAN's group (if any)" + help_text=_("VLAN's group (if any)") ) vlan = CSVModelChoiceField( queryset=VLAN.objects.all(), required=False, to_field_name='vid', - help_text="Assigned VLAN" + help_text=_("Assigned VLAN") ) status = CSVChoiceField( choices=PrefixStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) role = CSVModelChoiceField( queryset=Role.objects.all(), required=False, to_field_name='name', - help_text='Functional role' + help_text=_('Functional role') ) class Meta: @@ -181,23 +182,23 @@ class IPRangeCSVForm(NetBoxModelCSVForm): queryset=VRF.objects.all(), to_field_name='name', required=False, - help_text='Assigned VRF' + help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) status = CSVChoiceField( choices=IPRangeStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) role = CSVModelChoiceField( queryset=Role.objects.all(), required=False, to_field_name='name', - help_text='Functional role' + help_text=_('Functional role') ) class Meta: @@ -212,43 +213,43 @@ class IPAddressCSVForm(NetBoxModelCSVForm): queryset=VRF.objects.all(), to_field_name='name', required=False, - help_text='Assigned VRF' + help_text=_('Assigned VRF') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), to_field_name='name', required=False, - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) status = CSVChoiceField( choices=IPAddressStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) role = CSVChoiceField( choices=IPAddressRoleChoices, required=False, - help_text='Functional role' + help_text=_('Functional role') ) device = CSVModelChoiceField( queryset=Device.objects.all(), required=False, to_field_name='name', - help_text='Parent device of assigned interface (if any)' + help_text=_('Parent device of assigned interface (if any)') ) virtual_machine = CSVModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', - help_text='Parent VM of assigned interface (if any)' + help_text=_('Parent VM of assigned interface (if any)') ) interface = CSVModelChoiceField( queryset=Interface.objects.none(), # Can also refer to VMInterface required=False, to_field_name='name', - help_text='Assigned interface' + help_text=_('Assigned interface') ) is_primary = forms.BooleanField( - help_text='Make this the primary IP for the assigned device', + help_text=_('Make this the primary IP for the assigned device'), required=False ) @@ -333,7 +334,7 @@ class VLANGroupCSVForm(NetBoxModelCSVForm): scope_type = CSVContentTypeField( queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), required=False, - label='Scope type (app & model)' + label=_('Scope type (app & model)') ) min_vid = forms.IntegerField( min_value=VLAN_VID_MIN, @@ -361,29 +362,29 @@ class VLANCSVForm(NetBoxModelCSVForm): queryset=Site.objects.all(), required=False, to_field_name='name', - help_text='Assigned site' + help_text=_('Assigned site') ) group = CSVModelChoiceField( queryset=VLANGroup.objects.all(), required=False, to_field_name='name', - help_text='Assigned VLAN group' + help_text=_('Assigned VLAN group') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), to_field_name='name', required=False, - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) status = CSVChoiceField( choices=VLANStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) role = CSVModelChoiceField( queryset=Role.objects.all(), required=False, to_field_name='name', - help_text='Functional role' + help_text=_('Functional role') ) class Meta: @@ -398,7 +399,7 @@ class VLANCSVForm(NetBoxModelCSVForm): class ServiceTemplateCSVForm(NetBoxModelCSVForm): protocol = CSVChoiceField( choices=ServiceProtocolChoices, - help_text='IP protocol' + help_text=_('IP protocol') ) class Meta: @@ -411,17 +412,17 @@ class ServiceCSVForm(NetBoxModelCSVForm): queryset=Device.objects.all(), required=False, to_field_name='name', - help_text='Required if not assigned to a VM' + help_text=_('Required if not assigned to a VM') ) virtual_machine = CSVModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', - help_text='Required if not assigned to a device' + help_text=_('Required if not assigned to a device') ) protocol = CSVChoiceField( choices=ServiceProtocolChoices, - help_text='IP protocol' + help_text=_('IP protocol') ) class Meta: @@ -437,7 +438,7 @@ class L2VPNCSVForm(NetBoxModelCSVForm): ) type = CSVChoiceField( choices=L2VPNTypeChoices, - help_text='L2VPN type' + help_text=_('L2VPN type') ) class Meta: @@ -450,31 +451,31 @@ class L2VPNTerminationCSVForm(NetBoxModelCSVForm): queryset=L2VPN.objects.all(), required=True, to_field_name='name', - label='L2VPN', + label=_('L2VPN'), ) device = CSVModelChoiceField( queryset=Device.objects.all(), required=False, to_field_name='name', - help_text='Parent device (for interface)' + help_text=_('Parent device (for interface)') ) virtual_machine = CSVModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, to_field_name='name', - help_text='Parent virtual machine (for interface)' + help_text=_('Parent virtual machine (for interface)') ) interface = CSVModelChoiceField( queryset=Interface.objects.none(), # Can also refer to VMInterface required=False, to_field_name='name', - help_text='Assigned interface (device or VM)' + help_text=_('Assigned interface (device or VM)') ) vlan = CSVModelChoiceField( queryset=VLAN.objects.all(), required=False, to_field_name='name', - help_text='Assigned VLAN' + help_text=_('Assigned VLAN') ) class Meta: diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py index 7d277b33b..1a1496d7b 100644 --- a/netbox/ipam/forms/filtersets.py +++ b/netbox/ipam/forms/filtersets.py @@ -397,13 +397,13 @@ class VLANGroupFilterForm(NetBoxModelFilterSetForm): required=False, min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, - label='Minimum VID' + label=_('Minimum VID') ) max_vid = forms.IntegerField( required=False, min_value=VLAN_VID_MIN, max_value=VLAN_VID_MAX, - label='Maximum VID' + label=_('Maximum VID') ) tag = TagFilterField(model) diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index 9a5abc082..56c0631f4 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -1,6 +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 dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup from ipam.choices import * @@ -67,7 +68,7 @@ class VRFForm(TenancyForm, NetBoxModelForm): 'rd': "RD", } help_texts = { - 'rd': "Route distinguisher in any format", + 'rd': _("Route distinguisher in any format"), } @@ -104,7 +105,7 @@ class RIRForm(NetBoxModelForm): class AggregateForm(TenancyForm, NetBoxModelForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), - label='RIR' + label=_('RIR') ) comments = CommentField() @@ -119,8 +120,8 @@ class AggregateForm(TenancyForm, NetBoxModelForm): 'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'comments', 'tags', ] help_texts = { - 'prefix': "IPv4 or IPv6 network", - 'rir': "Regional Internet Registry responsible for this prefix", + 'prefix': _("IPv4 or IPv6 network"), + 'rir': _("Regional Internet Registry responsible for this prefix"), } widgets = { 'date_added': DatePicker(), @@ -130,11 +131,11 @@ class AggregateForm(TenancyForm, NetBoxModelForm): class ASNForm(TenancyForm, NetBoxModelForm): rir = DynamicModelChoiceField( queryset=RIR.objects.all(), - label='RIR', + label=_('RIR'), ) sites = DynamicModelMultipleChoiceField( queryset=Site.objects.all(), - label='Sites', + label=_('Sites'), required=False ) comments = CommentField() @@ -150,8 +151,8 @@ class ASNForm(TenancyForm, NetBoxModelForm): 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'comments', 'tags' ] help_texts = { - 'asn': "AS number", - 'rir': "Regional Internet Registry responsible for this prefix", + 'asn': _("AS number"), + 'rir': _("Regional Internet Registry responsible for this prefix"), } widgets = { 'date_added': DatePicker(), @@ -189,7 +190,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) region = DynamicModelChoiceField( queryset=Region.objects.all(), @@ -217,7 +218,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm): vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group', + label=_('VLAN group'), null_option='None', query_params={ 'site': '$site' @@ -229,7 +230,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm): vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, - label='VLAN', + label=_('VLAN'), query_params={ 'site_id': '$site', 'group_id': '$vlan_group', @@ -262,7 +263,7 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) role = DynamicModelChoiceField( queryset=Role.objects.all(), @@ -311,7 +312,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): vminterface = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Interface', + label=_('Interface'), query_params={ 'virtual_machine_id': '$virtual_machine' } @@ -319,17 +320,17 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): fhrpgroup = DynamicModelChoiceField( queryset=FHRPGroup.objects.all(), required=False, - label='FHRP Group' + label=_('FHRP Group') ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) nat_region = DynamicModelChoiceField( queryset=Region.objects.all(), required=False, - label='Region', + label=_('Region'), initial_params={ 'sites': '$nat_site' } @@ -337,7 +338,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_site_group = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), required=False, - label='Site group', + label=_('Site group'), initial_params={ 'sites': '$nat_site' } @@ -345,7 +346,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_site = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - label='Site', + label=_('Site'), query_params={ 'region_id': '$nat_region', 'group_id': '$nat_site_group', @@ -354,7 +355,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_rack = DynamicModelChoiceField( queryset=Rack.objects.all(), required=False, - label='Rack', + label=_('Rack'), null_option='None', query_params={ 'site_id': '$site' @@ -363,7 +364,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_device = DynamicModelChoiceField( queryset=Device.objects.all(), required=False, - label='Device', + label=_('Device'), query_params={ 'site_id': '$site', 'rack_id': '$nat_rack', @@ -372,12 +373,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_cluster = DynamicModelChoiceField( queryset=Cluster.objects.all(), required=False, - label='Cluster' + label=_('Cluster') ) nat_virtual_machine = DynamicModelChoiceField( queryset=VirtualMachine.objects.all(), required=False, - label='Virtual Machine', + label=_('Virtual Machine'), query_params={ 'cluster_id': '$nat_cluster', } @@ -385,12 +386,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): nat_vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) nat_inside = DynamicModelChoiceField( queryset=IPAddress.objects.all(), required=False, - label='IP Address', + label=_('IP Address'), query_params={ 'device_id': '$nat_device', 'virtual_machine_id': '$nat_virtual_machine', @@ -399,7 +400,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): ) primary_for_parent = forms.BooleanField( required=False, - label='Make this the primary IP for the device/VM' + label=_('Make this the primary IP for the device/VM') ) comments = CommentField() @@ -500,7 +501,7 @@ class IPAddressBulkAddForm(TenancyForm, NetBoxModelForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) class Meta: @@ -518,11 +519,11 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form): vrf_id = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) q = forms.CharField( required=False, - label='Search', + label=_('Search'), ) @@ -532,16 +533,16 @@ class FHRPGroupForm(NetBoxModelForm): ip_vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) ip_address = IPNetworkFormField( required=False, - label='Address' + label=_('Address') ) ip_status = forms.ChoiceField( choices=add_blank_choice(IPAddressStatusChoices), required=False, - label='Status' + label=_('Status') ) comments = CommentField() @@ -633,7 +634,7 @@ class VLANGroupForm(NetBoxModelForm): initial_params={ 'sites': '$site' }, - label='Site group' + label=_('Site group') ) site = DynamicModelChoiceField( queryset=Site.objects.all(), @@ -670,7 +671,7 @@ class VLANGroupForm(NetBoxModelForm): initial_params={ 'clusters': '$cluster' }, - label='Cluster group' + label=_('Cluster group') ) cluster = DynamicModelChoiceField( queryset=Cluster.objects.all(), @@ -734,7 +735,7 @@ class VLANForm(TenancyForm, NetBoxModelForm): ), required=False, widget=StaticSelect, - label='Group scope' + label=_('Group scope') ) group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), @@ -742,7 +743,7 @@ class VLANForm(TenancyForm, NetBoxModelForm): query_params={ 'scope_type': '$scope_type', }, - label='VLAN Group' + label=_('VLAN Group') ) # Site assignment fields @@ -752,7 +753,7 @@ class VLANForm(TenancyForm, NetBoxModelForm): initial_params={ 'sites': '$site' }, - label='Region' + label=_('Region') ) sitegroup = DynamicModelChoiceField( queryset=SiteGroup.objects.all(), @@ -760,7 +761,7 @@ class VLANForm(TenancyForm, NetBoxModelForm): initial_params={ 'sites': '$site' }, - label='Site group' + label=_('Site group') ) site = DynamicModelChoiceField( queryset=Site.objects.all(), @@ -786,12 +787,12 @@ class VLANForm(TenancyForm, NetBoxModelForm): 'tags', ] help_texts = { - 'site': "Leave blank if this VLAN spans multiple sites", - 'group': "VLAN group (optional)", - 'vid': "Configured VLAN ID", - 'name': "Configured VLAN name", - 'status': "Operational status of this VLAN", - 'role': "The primary function of this VLAN", + 'site': _("Leave blank if this VLAN spans multiple sites"), + 'group': _("VLAN group (optional)"), + 'vid': _("Configured VLAN ID"), + 'name': _("Configured VLAN name"), + 'status': _("Operational status of this VLAN"), + 'role': _("The primary function of this VLAN"), } widgets = { 'status': StaticSelect(), @@ -804,7 +805,7 @@ class ServiceTemplateForm(NetBoxModelForm): min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX ), - help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen." + help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.") ) comments = CommentField() @@ -836,12 +837,12 @@ class ServiceForm(NetBoxModelForm): min_value=SERVICE_PORT_MIN, max_value=SERVICE_PORT_MAX ), - help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen." + help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.") ) ipaddresses = DynamicModelMultipleChoiceField( queryset=IPAddress.objects.all(), required=False, - label='IP Addresses', + label=_('IP Addresses'), query_params={ 'device_id': '$device', 'virtual_machine_id': '$virtual_machine', @@ -855,8 +856,8 @@ class ServiceForm(NetBoxModelForm): 'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', ] help_texts = { - 'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be " - "reachable via all IPs assigned to the device.", + 'ipaddresses': _("IP address assignment is optional. If no IPs are selected, the service is assumed to be " + "reachable via all IPs assigned to the device."), } widgets = { 'protocol': StaticSelect(), @@ -937,12 +938,12 @@ class L2VPNTerminationForm(NetBoxModelForm): queryset=L2VPN.objects.all(), required=True, query_params={}, - label='L2VPN', + label=_('L2VPN'), fetch_trigger='open' ) device_vlan = DynamicModelChoiceField( queryset=Device.objects.all(), - label="Available on Device", + label=_("Available on Device"), required=False, query_params={} ) @@ -952,7 +953,7 @@ class L2VPNTerminationForm(NetBoxModelForm): query_params={ 'available_on_device': '$device_vlan' }, - label='VLAN' + label=_('VLAN') ) device = DynamicModelChoiceField( queryset=Device.objects.all(), @@ -977,7 +978,7 @@ class L2VPNTerminationForm(NetBoxModelForm): query_params={ 'virtual_machine_id': '$virtual_machine' }, - label='Interface' + label=_('Interface') ) class Meta: diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index bf9bd6d7f..dd92f97cc 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -6,6 +6,7 @@ from django.db import models from django.db.models import F from django.urls import reverse from django.utils.functional import cached_property +from django.utils.translation import gettext as _ from dcim.fields import ASNField from dcim.models import Device @@ -64,7 +65,7 @@ class RIR(OrganizationalModel): is_private = models.BooleanField( default=False, verbose_name='Private', - help_text='IP space managed by this RIR is considered private' + help_text=_('IP space managed by this RIR is considered private') ) class Meta: @@ -84,7 +85,7 @@ class ASN(PrimaryModel): asn = ASNField( unique=True, verbose_name='ASN', - help_text='32-bit autonomous system number' + help_text=_('32-bit autonomous system number') ) rir = models.ForeignKey( to='ipam.RIR', @@ -263,7 +264,7 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel): assigned to a VLAN where appropriate. """ prefix = IPNetworkField( - help_text='IPv4 or IPv6 network with mask' + help_text=_('IPv4 or IPv6 network with mask') ) site = models.ForeignKey( to='dcim.Site', @@ -300,7 +301,7 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel): choices=PrefixStatusChoices, default=PrefixStatusChoices.STATUS_ACTIVE, verbose_name='Status', - help_text='Operational status of this prefix' + help_text=_('Operational status of this prefix') ) role = models.ForeignKey( to='ipam.Role', @@ -308,16 +309,16 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel): related_name='prefixes', blank=True, null=True, - help_text='The primary function of this prefix' + help_text=_('The primary function of this prefix') ) is_pool = models.BooleanField( verbose_name='Is a pool', default=False, - help_text='All IP addresses within this prefix are considered usable' + help_text=_('All IP addresses within this prefix are considered usable') ) mark_utilized = models.BooleanField( default=False, - help_text="Treat as 100% utilized" + help_text=_("Treat as 100% utilized") ) # Cached depth & child counts @@ -538,10 +539,10 @@ class IPRange(PrimaryModel): A range of IP addresses, defined by start and end addresses. """ start_address = IPAddressField( - help_text='IPv4 or IPv6 address (with mask)' + help_text=_('IPv4 or IPv6 address (with mask)') ) end_address = IPAddressField( - help_text='IPv4 or IPv6 address (with mask)' + help_text=_('IPv4 or IPv6 address (with mask)') ) size = models.PositiveIntegerField( editable=False @@ -565,7 +566,7 @@ class IPRange(PrimaryModel): max_length=50, choices=IPRangeStatusChoices, default=IPRangeStatusChoices.STATUS_ACTIVE, - help_text='Operational status of this range' + help_text=_('Operational status of this range') ) role = models.ForeignKey( to='ipam.Role', @@ -573,7 +574,7 @@ class IPRange(PrimaryModel): related_name='ip_ranges', blank=True, null=True, - help_text='The primary function of this range' + help_text=_('The primary function of this range') ) clone_fields = ( @@ -736,7 +737,7 @@ class IPAddress(PrimaryModel): which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP. """ address = IPAddressField( - help_text='IPv4 or IPv6 address (with mask)' + help_text=_('IPv4 or IPv6 address (with mask)') ) vrf = models.ForeignKey( to='ipam.VRF', @@ -757,13 +758,13 @@ class IPAddress(PrimaryModel): max_length=50, choices=IPAddressStatusChoices, default=IPAddressStatusChoices.STATUS_ACTIVE, - help_text='The operational status of this IP' + help_text=_('The operational status of this IP') ) role = models.CharField( max_length=50, choices=IPAddressRoleChoices, blank=True, - help_text='The functional role of this IP' + help_text=_('The functional role of this IP') ) assigned_object_type = models.ForeignKey( to=ContentType, @@ -788,14 +789,14 @@ class IPAddress(PrimaryModel): blank=True, null=True, verbose_name='NAT (Inside)', - help_text='The IP for which this address is the "outside" IP' + help_text=_('The IP for which this address is the "outside" IP') ) dns_name = models.CharField( max_length=255, blank=True, validators=[DNSValidator], verbose_name='DNS Name', - help_text='Hostname or FQDN (not case-sensitive)' + help_text=_('Hostname or FQDN (not case-sensitive)') ) objects = IPAddressManager() diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index 4f5d513cf..bf6c6a52e 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -4,6 +4,7 @@ from django.core.exceptions import ValidationError from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.urls import reverse +from django.utils.translation import gettext as _ from dcim.models import Interface from ipam.choices import * @@ -50,7 +51,7 @@ class VLANGroup(OrganizationalModel): MinValueValidator(VLAN_VID_MIN), MaxValueValidator(VLAN_VID_MAX) ), - help_text='Lowest permissible ID of a child VLAN' + help_text=_('Lowest permissible ID of a child VLAN') ) max_vid = models.PositiveSmallIntegerField( verbose_name='Maximum VLAN ID', @@ -59,7 +60,7 @@ class VLANGroup(OrganizationalModel): MinValueValidator(VLAN_VID_MIN), MaxValueValidator(VLAN_VID_MAX) ), - help_text='Highest permissible ID of a child VLAN' + help_text=_('Highest permissible ID of a child VLAN') ) class Meta: diff --git a/netbox/ipam/models/vrfs.py b/netbox/ipam/models/vrfs.py index 0f3c9793c..a1a53b3a7 100644 --- a/netbox/ipam/models/vrfs.py +++ b/netbox/ipam/models/vrfs.py @@ -1,5 +1,6 @@ from django.db import models from django.urls import reverse +from django.utils.translation import gettext as _ from ipam.constants import * from netbox.models import PrimaryModel @@ -26,7 +27,7 @@ class VRF(PrimaryModel): blank=True, null=True, verbose_name='Route distinguisher', - help_text='Unique route distinguisher (as defined in RFC 4364)' + help_text=_('Unique route distinguisher (as defined in RFC 4364)') ) tenant = models.ForeignKey( to='tenancy.Tenant', @@ -38,7 +39,7 @@ class VRF(PrimaryModel): enforce_unique = models.BooleanField( default=True, verbose_name='Enforce unique space', - help_text='Prevent duplicate prefixes/IP addresses within this VRF' + help_text=_('Prevent duplicate prefixes/IP addresses within this VRF') ) import_targets = models.ManyToManyField( to='ipam.RouteTarget', @@ -76,7 +77,7 @@ class RouteTarget(PrimaryModel): name = models.CharField( max_length=VRF_RD_MAX_LENGTH, # Same format options as VRF RD (RFC 4360 section 4) unique=True, - help_text='Route target value (formatted in accordance with RFC 4360)' + help_text=_('Route target value (formatted in accordance with RFC 4360)') ) tenant = models.ForeignKey( to='tenancy.Tenant', diff --git a/netbox/netbox/config/parameters.py b/netbox/netbox/config/parameters.py index e2295888f..8efb0a033 100644 --- a/netbox/netbox/config/parameters.py +++ b/netbox/netbox/config/parameters.py @@ -1,5 +1,6 @@ from django import forms from django.contrib.postgres.forms import SimpleArrayField +from django.utils.translation import gettext_lazy as _ class ConfigParam: @@ -18,9 +19,9 @@ PARAMS = ( # Banners ConfigParam( name='BANNER_LOGIN', - label='Login banner', + label=_('Login banner'), default='', - description="Additional content to display on the login page", + description=_("Additional content to display on the login page"), field_kwargs={ 'widget': forms.Textarea( attrs={'class': 'vLargeTextField'} @@ -29,9 +30,9 @@ PARAMS = ( ), ConfigParam( name='BANNER_TOP', - label='Top banner', + label=_('Top banner'), default='', - description="Additional content to display at the top of every page", + description=_("Additional content to display at the top of every page"), field_kwargs={ 'widget': forms.Textarea( attrs={'class': 'vLargeTextField'} @@ -40,9 +41,9 @@ PARAMS = ( ), ConfigParam( name='BANNER_BOTTOM', - label='Bottom banner', + label=_('Bottom banner'), default='', - description="Additional content to display at the bottom of every page", + description=_("Additional content to display at the bottom of every page"), field_kwargs={ 'widget': forms.Textarea( attrs={'class': 'vLargeTextField'} @@ -53,69 +54,69 @@ PARAMS = ( # IPAM ConfigParam( name='ENFORCE_GLOBAL_UNIQUE', - label='Globally unique IP space', + label=_('Globally unique IP space'), default=False, - description="Enforce unique IP addressing within the global table", + description=_("Enforce unique IP addressing within the global table"), field=forms.BooleanField ), ConfigParam( name='PREFER_IPV4', - label='Prefer IPv4', + label=_('Prefer IPv4'), default=False, - description="Prefer IPv4 addresses over IPv6", + description=_("Prefer IPv4 addresses over IPv6"), field=forms.BooleanField ), # Racks ConfigParam( name='RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', - label='Rack unit height', + label=_('Rack unit height'), default=22, - description="Default unit height for rendered rack elevations", + description=_("Default unit height for rendered rack elevations"), field=forms.IntegerField ), ConfigParam( name='RACK_ELEVATION_DEFAULT_UNIT_WIDTH', - label='Rack unit width', + label=_('Rack unit width'), default=220, - description="Default unit width for rendered rack elevations", + description=_("Default unit width for rendered rack elevations"), field=forms.IntegerField ), # Power ConfigParam( name='POWERFEED_DEFAULT_VOLTAGE', - label='Powerfeed voltage', + label=_('Powerfeed voltage'), default=120, - description="Default voltage for powerfeeds", + description=_("Default voltage for powerfeeds"), field=forms.IntegerField ), ConfigParam( name='POWERFEED_DEFAULT_AMPERAGE', - label='Powerfeed amperage', + label=_('Powerfeed amperage'), default=15, - description="Default amperage for powerfeeds", + description=_("Default amperage for powerfeeds"), field=forms.IntegerField ), ConfigParam( name='POWERFEED_DEFAULT_MAX_UTILIZATION', - label='Powerfeed max utilization', + label=_('Powerfeed max utilization'), default=80, - description="Default max utilization for powerfeeds", + description=_("Default max utilization for powerfeeds"), field=forms.IntegerField ), # Security ConfigParam( name='ALLOWED_URL_SCHEMES', - label='Allowed URL schemes', + label=_('Allowed URL schemes'), default=( 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'xmpp', ), - description="Permitted schemes for URLs in user-provided content", + description=_("Permitted schemes for URLs in user-provided content"), field=SimpleArrayField, field_kwargs={'base_field': forms.CharField()} ), @@ -123,13 +124,13 @@ PARAMS = ( # Pagination ConfigParam( name='PAGINATE_COUNT', - label='Default page size', + label=_('Default page size'), default=50, field=forms.IntegerField ), ConfigParam( name='MAX_PAGE_SIZE', - label='Maximum page size', + label=_('Maximum page size'), default=1000, field=forms.IntegerField ), @@ -137,9 +138,9 @@ PARAMS = ( # Validation ConfigParam( name='CUSTOM_VALIDATORS', - label='Custom validators', + label=_('Custom validators'), default={}, - description="Custom validation rules (JSON)", + description=_("Custom validation rules (JSON)"), field=forms.JSONField, field_kwargs={ 'widget': forms.Textarea( @@ -151,28 +152,28 @@ PARAMS = ( # NAPALM ConfigParam( name='NAPALM_USERNAME', - label='NAPALM username', + label=_('NAPALM username'), default='', - description="Username to use when connecting to devices via NAPALM" + description=_("Username to use when connecting to devices via NAPALM") ), ConfigParam( name='NAPALM_PASSWORD', - label='NAPALM password', + label=_('NAPALM password'), default='', - description="Password to use when connecting to devices via NAPALM" + description=_("Password to use when connecting to devices via NAPALM") ), ConfigParam( name='NAPALM_TIMEOUT', - label='NAPALM timeout', + label=_('NAPALM timeout'), default=30, - description="NAPALM connection timeout (in seconds)", + description=_("NAPALM connection timeout (in seconds)"), field=forms.IntegerField ), ConfigParam( name='NAPALM_ARGS', - label='NAPALM arguments', + label=_('NAPALM arguments'), default={}, - description="Additional arguments to pass when invoking a NAPALM driver (as JSON data)", + description=_("Additional arguments to pass when invoking a NAPALM driver (as JSON data)"), field=forms.JSONField, field_kwargs={ 'widget': forms.Textarea( @@ -184,46 +185,46 @@ PARAMS = ( # User preferences ConfigParam( name='DEFAULT_USER_PREFERENCES', - label='Default preferences', + label=_('Default preferences'), default={}, - description="Default preferences for new users", + description=_("Default preferences for new users"), field=forms.JSONField ), # Miscellaneous ConfigParam( name='MAINTENANCE_MODE', - label='Maintenance mode', + label=_('Maintenance mode'), default=False, - description="Enable maintenance mode", + description=_("Enable maintenance mode"), field=forms.BooleanField ), ConfigParam( name='GRAPHQL_ENABLED', - label='GraphQL enabled', + label=_('GraphQL enabled'), default=True, - description="Enable the GraphQL API", + description=_("Enable the GraphQL API"), field=forms.BooleanField ), ConfigParam( name='CHANGELOG_RETENTION', - label='Changelog retention', + label=_('Changelog retention'), default=90, - description="Days to retain changelog history (set to zero for unlimited)", + description=_("Days to retain changelog history (set to zero for unlimited)"), field=forms.IntegerField ), ConfigParam( name='JOBRESULT_RETENTION', - label='Job result retention', + label=_('Job result retention'), default=90, - description="Days to retain job result history (set to zero for unlimited)", + description=_("Days to retain job result history (set to zero for unlimited)"), field=forms.IntegerField ), ConfigParam( name='MAPS_URL', - label='Maps URL', + label=_('Maps URL'), default='https://maps.google.com/?q=', - description="Base URL for mapping geographic locations" + description=_("Base URL for mapping geographic locations") ), ) diff --git a/netbox/netbox/filtersets.py b/netbox/netbox/filtersets.py index 02ccdca50..8c39db287 100644 --- a/netbox/netbox/filtersets.py +++ b/netbox/netbox/filtersets.py @@ -5,6 +5,7 @@ from django.db import models from django_filters.exceptions import FieldLookupError from django_filters.utils import get_model_field, resolve_field from django.shortcuts import get_object_or_404 +from django.utils.translation import gettext as _ from extras.choices import CustomFieldFilterLogicChoices from extras.filters import TagFilter @@ -235,7 +236,7 @@ class NetBoxModelFilterSet(ChangeLoggedModelFilterSet): """ q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) tag = TagFilter() diff --git a/netbox/netbox/forms/__init__.py b/netbox/netbox/forms/__init__.py index dd1fb7726..fd4998274 100644 --- a/netbox/netbox/forms/__init__.py +++ b/netbox/netbox/forms/__init__.py @@ -17,7 +17,7 @@ LOOKUP_CHOICES = ( class SearchForm(BootstrapMixin, forms.Form): q = forms.CharField( - label='Search', + label=_('Search'), widget=forms.TextInput( attrs={ 'hx-get': '', @@ -29,7 +29,7 @@ class SearchForm(BootstrapMixin, forms.Form): obj_types = forms.MultipleChoiceField( choices=[], required=False, - label='Object type(s)', + label=_('Object type(s)'), widget=StaticSelectMultiple() ) lookup = forms.ChoiceField( diff --git a/netbox/netbox/forms/base.py b/netbox/netbox/forms/base.py index 4a4368a65..2d785400c 100644 --- a/netbox/netbox/forms/base.py +++ b/netbox/netbox/forms/base.py @@ -2,6 +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 extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices, CustomFieldVisibilityChoices from extras.forms.mixins import CustomFieldsMixin, SavedFiltersMixin @@ -132,7 +133,7 @@ class NetBoxModelFilterSetForm(BootstrapMixin, CustomFieldsMixin, SavedFiltersMi """ q = forms.CharField( required=False, - label='Search' + label=_('Search') ) def __init__(self, *args, **kwargs): diff --git a/netbox/netbox/navigation/menu.py b/netbox/netbox/navigation/menu.py index dcec76d91..a912c84d5 100644 --- a/netbox/netbox/navigation/menu.py +++ b/netbox/netbox/navigation/menu.py @@ -1,119 +1,120 @@ +from django.utils.translation import gettext as _ + from netbox.registry import registry from . import * - # # Nav menus # ORGANIZATION_MENU = Menu( - label='Organization', + label=_('Organization'), icon_class='mdi mdi-domain', groups=( MenuGroup( - label='Sites', + label=_('Sites'), items=( - get_model_item('dcim', 'site', 'Sites'), - get_model_item('dcim', 'region', 'Regions'), - get_model_item('dcim', 'sitegroup', 'Site Groups'), - get_model_item('dcim', 'location', 'Locations'), + get_model_item('dcim', 'site', _('Sites')), + get_model_item('dcim', 'region', _('Regions')), + get_model_item('dcim', 'sitegroup', _('Site Groups')), + get_model_item('dcim', 'location', _('Locations')), ), ), MenuGroup( - label='Racks', + label=_('Racks'), items=( - get_model_item('dcim', 'rack', 'Racks'), - get_model_item('dcim', 'rackrole', 'Rack Roles'), - get_model_item('dcim', 'rackreservation', 'Reservations'), + get_model_item('dcim', 'rack', _('Racks')), + get_model_item('dcim', 'rackrole', _('Rack Roles')), + get_model_item('dcim', 'rackreservation', _('Reservations')), MenuItem( link='dcim:rack_elevation_list', - link_text='Elevations', + link_text=_('Elevations'), permissions=['dcim.view_rack'] ), ), ), MenuGroup( - label='Tenancy', + label=_('Tenancy'), items=( - get_model_item('tenancy', 'tenant', 'Tenants'), - get_model_item('tenancy', 'tenantgroup', 'Tenant Groups'), + get_model_item('tenancy', 'tenant', _('Tenants')), + get_model_item('tenancy', 'tenantgroup', _('Tenant Groups')), ), ), MenuGroup( - label='Contacts', + label=_('Contacts'), items=( - get_model_item('tenancy', 'contact', 'Contacts'), - get_model_item('tenancy', 'contactgroup', 'Contact Groups'), - get_model_item('tenancy', 'contactrole', 'Contact Roles'), + get_model_item('tenancy', 'contact', _('Contacts')), + get_model_item('tenancy', 'contactgroup', _('Contact Groups')), + get_model_item('tenancy', 'contactrole', _('Contact Roles')), ), ), ), ) DEVICES_MENU = Menu( - label='Devices', + label=_('Devices'), icon_class='mdi mdi-server', groups=( MenuGroup( - label='Devices', + label=_('Devices'), items=( - get_model_item('dcim', 'device', 'Devices'), - get_model_item('dcim', 'module', 'Modules'), - get_model_item('dcim', 'devicerole', 'Device Roles'), - get_model_item('dcim', 'platform', 'Platforms'), - get_model_item('dcim', 'virtualchassis', 'Virtual Chassis'), - get_model_item('dcim', 'virtualdevicecontext', 'Virtual Device Contexts'), + get_model_item('dcim', 'device', _('Devices')), + get_model_item('dcim', 'module', _('Modules')), + get_model_item('dcim', 'devicerole', _('Device Roles')), + get_model_item('dcim', 'platform', _('Platforms')), + get_model_item('dcim', 'virtualchassis', _('Virtual Chassis')), + get_model_item('dcim', 'virtualdevicecontext', _('Virtual Device Contexts')), ), ), MenuGroup( - label='Device Types', + label=_('Device Types'), items=( - get_model_item('dcim', 'devicetype', 'Device Types'), - get_model_item('dcim', 'moduletype', 'Module Types'), - get_model_item('dcim', 'manufacturer', 'Manufacturers'), + get_model_item('dcim', 'devicetype', _('Device Types')), + get_model_item('dcim', 'moduletype', _('Module Types')), + get_model_item('dcim', 'manufacturer', _('Manufacturers')), ), ), MenuGroup( - label='Device Components', + label=_('Device Components'), items=( - get_model_item('dcim', 'interface', 'Interfaces', actions=['import']), - get_model_item('dcim', 'frontport', 'Front Ports', actions=['import']), - get_model_item('dcim', 'rearport', 'Rear Ports', actions=['import']), - get_model_item('dcim', 'consoleport', 'Console Ports', actions=['import']), - get_model_item('dcim', 'consoleserverport', 'Console Server Ports', actions=['import']), - get_model_item('dcim', 'powerport', 'Power Ports', actions=['import']), - get_model_item('dcim', 'poweroutlet', 'Power Outlets', actions=['import']), - get_model_item('dcim', 'modulebay', 'Module Bays', actions=['import']), - get_model_item('dcim', 'devicebay', 'Device Bays', actions=['import']), - get_model_item('dcim', 'inventoryitem', 'Inventory Items', actions=['import']), - get_model_item('dcim', 'inventoryitemrole', 'Inventory Item Roles'), + get_model_item('dcim', 'interface', _('Interfaces'), actions=['import']), + get_model_item('dcim', 'frontport', _('Front Ports'), actions=['import']), + get_model_item('dcim', 'rearport', _('Rear Ports'), actions=['import']), + get_model_item('dcim', 'consoleport', _('Console Ports'), actions=['import']), + get_model_item('dcim', 'consoleserverport', _('Console Server Ports'), actions=['import']), + get_model_item('dcim', 'powerport', _('Power Ports'), actions=['import']), + get_model_item('dcim', 'poweroutlet', _('Power Outlets'), actions=['import']), + get_model_item('dcim', 'modulebay', _('Module Bays'), actions=['import']), + get_model_item('dcim', 'devicebay', _('Device Bays'), actions=['import']), + get_model_item('dcim', 'inventoryitem', _('Inventory Items'), actions=['import']), + get_model_item('dcim', 'inventoryitemrole', _('Inventory Item Roles')), ), ), ), ) CONNECTIONS_MENU = Menu( - label='Connections', + label=_('Connections'), icon_class='mdi mdi-connection', groups=( MenuGroup( - label='Connections', + label=_('Connections'), items=( - get_model_item('dcim', 'cable', 'Cables', actions=['import']), - get_model_item('wireless', 'wirelesslink', 'Wireless Links', actions=['import']), + get_model_item('dcim', 'cable', _('Cables'), actions=['import']), + get_model_item('wireless', 'wirelesslink', _('Wireless Links'), actions=['import']), MenuItem( link='dcim:interface_connections_list', - link_text='Interface Connections', + link_text=_('Interface Connections'), permissions=['dcim.view_interface'] ), MenuItem( link='dcim:console_connections_list', - link_text='Console Connections', + link_text=_('Console Connections'), permissions=['dcim.view_consoleport'] ), MenuItem( link='dcim:power_connections_list', - link_text='Power Connections', + link_text=_('Power Connections'), permissions=['dcim.view_powerport'] ), ), @@ -122,192 +123,192 @@ CONNECTIONS_MENU = Menu( ) WIRELESS_MENU = Menu( - label='Wireless', + label=_('Wireless'), icon_class='mdi mdi-wifi', groups=( MenuGroup( - label='Wireless', + label=_('Wireless'), items=( - get_model_item('wireless', 'wirelesslan', 'Wireless LANs'), - get_model_item('wireless', 'wirelesslangroup', 'Wireless LAN Groups'), + get_model_item('wireless', 'wirelesslan', _('Wireless LANs')), + get_model_item('wireless', 'wirelesslangroup', _('Wireless LAN Groups')), ), ), ), ) IPAM_MENU = Menu( - label='IPAM', + label=_('IPAM'), icon_class='mdi mdi-counter', groups=( MenuGroup( - label='IP Addresses', + label=_('IP Addresses'), items=( - get_model_item('ipam', 'ipaddress', 'IP Addresses'), - get_model_item('ipam', 'iprange', 'IP Ranges'), + get_model_item('ipam', 'ipaddress', _('IP Addresses')), + get_model_item('ipam', 'iprange', _('IP Ranges')), ), ), MenuGroup( - label='Prefixes', + label=_('Prefixes'), items=( - get_model_item('ipam', 'prefix', 'Prefixes'), - get_model_item('ipam', 'role', 'Prefix & VLAN Roles'), + get_model_item('ipam', 'prefix', _('Prefixes')), + get_model_item('ipam', 'role', _('Prefix & VLAN Roles')), ), ), MenuGroup( - label='ASNs', + label=_('ASNs'), items=( - get_model_item('ipam', 'asn', 'ASNs'), + get_model_item('ipam', 'asn', _('ASNs')), ), ), MenuGroup( - label='Aggregates', + label=_('Aggregates'), items=( - get_model_item('ipam', 'aggregate', 'Aggregates'), - get_model_item('ipam', 'rir', 'RIRs'), + get_model_item('ipam', 'aggregate', _('Aggregates')), + get_model_item('ipam', 'rir', _('RIRs')), ), ), MenuGroup( - label='VRFs', + label=_('VRFs'), items=( - get_model_item('ipam', 'vrf', 'VRFs'), - get_model_item('ipam', 'routetarget', 'Route Targets'), + get_model_item('ipam', 'vrf', _('VRFs')), + get_model_item('ipam', 'routetarget', _('Route Targets')), ), ), MenuGroup( - label='VLANs', + label=_('VLANs'), items=( - get_model_item('ipam', 'vlan', 'VLANs'), - get_model_item('ipam', 'vlangroup', 'VLAN Groups'), + get_model_item('ipam', 'vlan', _('VLANs')), + get_model_item('ipam', 'vlangroup', _('VLAN Groups')), ), ), MenuGroup( - label='Other', + label=_('Other'), items=( - get_model_item('ipam', 'fhrpgroup', 'FHRP Groups'), - get_model_item('ipam', 'servicetemplate', 'Service Templates'), - get_model_item('ipam', 'service', 'Services'), + get_model_item('ipam', 'fhrpgroup', _('FHRP Groups')), + get_model_item('ipam', 'servicetemplate', _('Service Templates')), + get_model_item('ipam', 'service', _('Services')), ), ), ), ) OVERLAY_MENU = Menu( - label='Overlay', + label=_('Overlay'), icon_class='mdi mdi-graph-outline', groups=( MenuGroup( label='L2VPNs', items=( - get_model_item('ipam', 'l2vpn', 'L2VPNs'), - get_model_item('ipam', 'l2vpntermination', 'Terminations'), + get_model_item('ipam', 'l2vpn', _('L2VPNs')), + get_model_item('ipam', 'l2vpntermination', _('Terminations')), ), ), ), ) VIRTUALIZATION_MENU = Menu( - label='Virtualization', + label=_('Virtualization'), icon_class='mdi mdi-monitor', groups=( MenuGroup( - label='Virtual Machines', + label=_('Virtual Machines'), items=( - get_model_item('virtualization', 'virtualmachine', 'Virtual Machines'), - get_model_item('virtualization', 'vminterface', 'Interfaces', actions=['import']), + get_model_item('virtualization', 'virtualmachine', _('Virtual Machines')), + get_model_item('virtualization', 'vminterface', _('Interfaces'), actions=['import']), ), ), MenuGroup( - label='Clusters', + label=_('Clusters'), items=( - get_model_item('virtualization', 'cluster', 'Clusters'), - get_model_item('virtualization', 'clustertype', 'Cluster Types'), - get_model_item('virtualization', 'clustergroup', 'Cluster Groups'), + get_model_item('virtualization', 'cluster', _('Clusters')), + get_model_item('virtualization', 'clustertype', _('Cluster Types')), + get_model_item('virtualization', 'clustergroup', _('Cluster Groups')), ), ), ), ) CIRCUITS_MENU = Menu( - label='Circuits', + label=_('Circuits'), icon_class='mdi mdi-transit-connection-variant', groups=( MenuGroup( - label='Circuits', + label=_('Circuits'), items=( - get_model_item('circuits', 'circuit', 'Circuits'), - get_model_item('circuits', 'circuittype', 'Circuit Types'), + get_model_item('circuits', 'circuit', _('Circuits')), + get_model_item('circuits', 'circuittype', _('Circuit Types')), ), ), MenuGroup( - label='Providers', + label=_('Providers'), items=( - get_model_item('circuits', 'provider', 'Providers'), - get_model_item('circuits', 'providernetwork', 'Provider Networks'), + get_model_item('circuits', 'provider', _('Providers')), + get_model_item('circuits', 'providernetwork', _('Provider Networks')), ), ), ), ) POWER_MENU = Menu( - label='Power', + label=_('Power'), icon_class='mdi mdi-flash', groups=( MenuGroup( - label='Power', + label=_('Power'), items=( - get_model_item('dcim', 'powerfeed', 'Power Feeds'), - get_model_item('dcim', 'powerpanel', 'Power Panels'), + get_model_item('dcim', 'powerfeed', _('Power Feeds')), + get_model_item('dcim', 'powerpanel', _('Power Panels')), ), ), ), ) OTHER_MENU = Menu( - label='Other', + label=_('Other'), icon_class='mdi mdi-notification-clear-all', groups=( MenuGroup( - label='Logging', + label=_('Logging'), items=( - get_model_item('extras', 'journalentry', 'Journal Entries', actions=[]), - get_model_item('extras', 'objectchange', 'Change Log', actions=[]), + get_model_item('extras', 'journalentry', _('Journal Entries'), actions=[]), + get_model_item('extras', 'objectchange', _('Change Log'), actions=[]), ), ), MenuGroup( - label='Customization', + label=_('Customization'), items=( - get_model_item('extras', 'customfield', 'Custom Fields'), - get_model_item('extras', 'customlink', 'Custom Links'), - get_model_item('extras', 'exporttemplate', 'Export Templates'), - get_model_item('extras', 'savedfilter', 'Saved Filters'), + get_model_item('extras', 'customfield', _('Custom Fields')), + get_model_item('extras', 'customlink', _('Custom Links')), + get_model_item('extras', 'exporttemplate', _('Export Templates')), + get_model_item('extras', 'savedfilter', _('Saved Filters')), ), ), MenuGroup( - label='Integrations', + label=_('Integrations'), items=( - get_model_item('extras', 'webhook', 'Webhooks'), + get_model_item('extras', 'webhook', _('Webhooks')), MenuItem( link='extras:report_list', - link_text='Reports', + link_text=_('Reports'), permissions=['extras.view_report'] ), MenuItem( link='extras:script_list', - link_text='Scripts', + link_text=_('Scripts'), permissions=['extras.view_script'] ), MenuItem( link='extras:jobresult_list', - link_text='Job Results', + link_text=_('Job Results'), permissions=['extras.view_jobresult'], ), ), ), MenuGroup( - label='Other', + label=_('Other'), items=( get_model_item('extras', 'tag', 'Tags'), - get_model_item('extras', 'configcontext', 'Config Contexts', actions=['add']), + get_model_item('extras', 'configcontext', _('Config Contexts'), actions=['add']), ), ), ), @@ -342,7 +343,7 @@ if registry['plugins']['menu_items']: for label, items in registry['plugins']['menu_items'].items() ] plugins_menu = Menu( - label="Plugins", + label=_("Plugins"), icon_class="mdi mdi-puzzle", groups=groups ) diff --git a/netbox/netbox/preferences.py b/netbox/netbox/preferences.py index 95fd101c3..c88b56072 100644 --- a/netbox/netbox/preferences.py +++ b/netbox/netbox/preferences.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from netbox.registry import registry from users.preferences import UserPreference from utilities.paginator import EnhancedPaginator @@ -13,7 +14,7 @@ PREFERENCES = { # User interface 'ui.colormode': UserPreference( - label='Color mode', + label=_('Color mode'), choices=( ('light', 'Light'), ('dark', 'Dark'), @@ -21,25 +22,25 @@ PREFERENCES = { default='light', ), 'pagination.per_page': UserPreference( - label='Page length', + label=_('Page length'), choices=get_page_lengths(), - description='The number of objects to display per page', + description=_('The number of objects to display per page'), coerce=lambda x: int(x) ), 'pagination.placement': UserPreference( - label='Paginator placement', + label=_('Paginator placement'), choices=( ('bottom', 'Bottom'), ('top', 'Top'), ('both', 'Both'), ), - description='Where the paginator controls will be displayed relative to a table', + description=_('Where the paginator controls will be displayed relative to a table'), default='bottom' ), # Miscellaneous 'data_format': UserPreference( - label='Data format', + label=_('Data format'), choices=( ('json', 'JSON'), ('yaml', 'YAML'), diff --git a/netbox/tenancy/filtersets.py b/netbox/tenancy/filtersets.py index dd14a412b..ab74949ff 100644 --- a/netbox/tenancy/filtersets.py +++ b/netbox/tenancy/filtersets.py @@ -1,5 +1,6 @@ import django_filters from django.db.models import Q +from django.utils.translation import gettext as _ from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter @@ -25,13 +26,13 @@ __all__ = ( class ContactGroupFilterSet(OrganizationalModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=ContactGroup.objects.all(), - label='Contact group (ID)', + label=_('Contact group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=ContactGroup.objects.all(), to_field_name='slug', - label='Contact group (slug)', + label=_('Contact group (slug)'), ) class Meta: @@ -51,14 +52,14 @@ class ContactFilterSet(NetBoxModelFilterSet): queryset=ContactGroup.objects.all(), field_name='group', lookup_expr='in', - label='Contact group (ID)', + label=_('Contact group (ID)'), ) group = TreeNodeMultipleChoiceFilter( queryset=ContactGroup.objects.all(), field_name='group', lookup_expr='in', to_field_name='slug', - label='Contact group (slug)', + label=_('Contact group (slug)'), ) class Meta: @@ -83,17 +84,17 @@ class ContactAssignmentFilterSet(ChangeLoggedModelFilterSet): content_type = ContentTypeFilter() contact_id = django_filters.ModelMultipleChoiceFilter( queryset=Contact.objects.all(), - label='Contact (ID)', + label=_('Contact (ID)'), ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=ContactRole.objects.all(), - label='Contact role (ID)', + label=_('Contact role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=ContactRole.objects.all(), to_field_name='slug', - label='Contact role (slug)', + label=_('Contact role (slug)'), ) class Meta: @@ -105,18 +106,18 @@ class ContactModelFilterSet(django_filters.FilterSet): contact = django_filters.ModelMultipleChoiceFilter( field_name='contacts__contact', queryset=Contact.objects.all(), - label='Contact', + label=_('Contact'), ) contact_role = django_filters.ModelMultipleChoiceFilter( field_name='contacts__role', queryset=ContactRole.objects.all(), - label='Contact Role' + label=_('Contact Role') ) contact_group = TreeNodeMultipleChoiceFilter( queryset=ContactGroup.objects.all(), field_name='contacts__contact__group', lookup_expr='in', - label='Contact group', + label=_('Contact group'), ) @@ -127,13 +128,13 @@ class ContactModelFilterSet(django_filters.FilterSet): class TenantGroupFilterSet(OrganizationalModelFilterSet): parent_id = django_filters.ModelMultipleChoiceFilter( queryset=TenantGroup.objects.all(), - label='Tenant group (ID)', + label=_('Tenant group (ID)'), ) parent = django_filters.ModelMultipleChoiceFilter( field_name='parent__slug', queryset=TenantGroup.objects.all(), to_field_name='slug', - label='Tenant group (slug)', + label=_('Tenant group (slug)'), ) class Meta: @@ -146,14 +147,14 @@ class TenantFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): queryset=TenantGroup.objects.all(), field_name='group', lookup_expr='in', - label='Tenant group (ID)', + label=_('Tenant group (ID)'), ) group = TreeNodeMultipleChoiceFilter( queryset=TenantGroup.objects.all(), field_name='group', lookup_expr='in', to_field_name='slug', - label='Tenant group (slug)', + label=_('Tenant group (slug)'), ) class Meta: @@ -179,22 +180,22 @@ class TenancyFilterSet(django_filters.FilterSet): queryset=TenantGroup.objects.all(), field_name='tenant__group', lookup_expr='in', - label='Tenant Group (ID)', + label=_('Tenant Group (ID)'), ) tenant_group = TreeNodeMultipleChoiceFilter( queryset=TenantGroup.objects.all(), field_name='tenant__group', to_field_name='slug', lookup_expr='in', - label='Tenant Group (slug)', + label=_('Tenant Group (slug)'), ) tenant_id = django_filters.ModelMultipleChoiceFilter( queryset=Tenant.objects.all(), - label='Tenant (ID)', + label=_('Tenant (ID)'), ) tenant = django_filters.ModelMultipleChoiceFilter( queryset=Tenant.objects.all(), field_name='tenant__slug', to_field_name='slug', - label='Tenant (slug)', + label=_('Tenant (slug)'), ) diff --git a/netbox/tenancy/forms/bulk_import.py b/netbox/tenancy/forms/bulk_import.py index 137f79d42..27092f9e8 100644 --- a/netbox/tenancy/forms/bulk_import.py +++ b/netbox/tenancy/forms/bulk_import.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from netbox.forms import NetBoxModelCSVForm from tenancy.models import * from utilities.forms import CSVModelChoiceField, SlugField @@ -20,7 +21,7 @@ class TenantGroupCSVForm(NetBoxModelCSVForm): queryset=TenantGroup.objects.all(), required=False, to_field_name='name', - help_text='Parent group' + help_text=_('Parent group') ) slug = SlugField() @@ -35,7 +36,7 @@ class TenantCSVForm(NetBoxModelCSVForm): queryset=TenantGroup.objects.all(), required=False, to_field_name='name', - help_text='Assigned group' + help_text=_('Assigned group') ) class Meta: @@ -52,7 +53,7 @@ class ContactGroupCSVForm(NetBoxModelCSVForm): queryset=ContactGroup.objects.all(), required=False, to_field_name='name', - help_text='Parent group' + help_text=_('Parent group') ) slug = SlugField() @@ -74,7 +75,7 @@ class ContactCSVForm(NetBoxModelCSVForm): queryset=ContactGroup.objects.all(), required=False, to_field_name='name', - help_text='Assigned group' + help_text=_('Assigned group') ) class Meta: diff --git a/netbox/users/admin/forms.py b/netbox/users/admin/forms.py index 540735ecc..986ddd0aa 100644 --- a/netbox/users/admin/forms.py +++ b/netbox/users/admin/forms.py @@ -3,6 +3,7 @@ from django.contrib.auth.models import Group, User from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.contenttypes.models import ContentType from django.core.exceptions import FieldError, ValidationError +from django.utils.translation import gettext as _ from users.constants import CONSTRAINT_TOKEN_USER, OBJECTPERMISSION_OBJECT_TYPES from users.models import ObjectPermission, Token @@ -46,7 +47,7 @@ class GroupAdminForm(forms.ModelForm): class TokenAdminForm(forms.ModelForm): key = forms.CharField( required=False, - help_text="If no key is provided, one will be generated automatically." + help_text=_("If no key is provided, one will be generated automatically.") ) class Meta: @@ -70,10 +71,10 @@ class ObjectPermissionForm(forms.ModelForm): model = ObjectPermission exclude = [] help_texts = { - 'actions': 'Actions granted in addition to those listed above', - 'constraints': 'JSON expression of a queryset filter that will return only permitted objects. Leave null ' - 'to match all objects of this type. A list of multiple objects will result in a logical OR ' - 'operation.' + 'actions': _('Actions granted in addition to those listed above'), + 'constraints': _('JSON expression of a queryset filter that will return only permitted objects. Leave null ' + 'to match all objects of this type. A list of multiple objects will result in a logical OR ' + 'operation.') } labels = { 'actions': 'Additional actions' diff --git a/netbox/users/filtersets.py b/netbox/users/filtersets.py index 71246956b..4ae9df89a 100644 --- a/netbox/users/filtersets.py +++ b/netbox/users/filtersets.py @@ -1,6 +1,7 @@ import django_filters from django.contrib.auth.models import Group, User from django.db.models import Q +from django.utils.translation import gettext as _ from netbox.filtersets import BaseFilterSet from users.models import ObjectPermission, Token @@ -15,7 +16,7 @@ __all__ = ( class GroupFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) class Meta: @@ -31,18 +32,18 @@ class GroupFilterSet(BaseFilterSet): class UserFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) group_id = django_filters.ModelMultipleChoiceFilter( field_name='groups', queryset=Group.objects.all(), - label='Group', + label=_('Group'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='groups__name', queryset=Group.objects.all(), to_field_name='name', - label='Group (name)', + label=_('Group (name)'), ) class Meta: @@ -63,18 +64,18 @@ class UserFilterSet(BaseFilterSet): class TokenFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) user_id = django_filters.ModelMultipleChoiceFilter( field_name='user', queryset=User.objects.all(), - label='User', + label=_('User'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='user__username', queryset=User.objects.all(), to_field_name='username', - label='User (name)', + label=_('User (name)'), ) created = django_filters.DateTimeFilter() created__gte = django_filters.DateTimeFilter( @@ -111,29 +112,29 @@ class TokenFilterSet(BaseFilterSet): class ObjectPermissionFilterSet(BaseFilterSet): q = django_filters.CharFilter( method='search', - label='Search', + label=_('Search'), ) user_id = django_filters.ModelMultipleChoiceFilter( field_name='users', queryset=User.objects.all(), - label='User', + label=_('User'), ) user = django_filters.ModelMultipleChoiceFilter( field_name='users__username', queryset=User.objects.all(), to_field_name='username', - label='User (name)', + label=_('User (name)'), ) group_id = django_filters.ModelMultipleChoiceFilter( field_name='groups', queryset=Group.objects.all(), - label='Group', + label=_('Group'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='groups__name', queryset=Group.objects.all(), to_field_name='name', - label='Group (name)', + label=_('Group (name)'), ) class Meta: diff --git a/netbox/users/forms.py b/netbox/users/forms.py index 048005f13..e8647aa5f 100644 --- a/netbox/users/forms.py +++ b/netbox/users/forms.py @@ -3,6 +3,7 @@ from django.conf import settings from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm from django.contrib.postgres.forms import SimpleArrayField from django.utils.html import mark_safe +from django.utils.translation import gettext as _ from ipam.formfields import IPNetworkFormField from netbox.preferences import PREFERENCES @@ -100,14 +101,14 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMe class TokenForm(BootstrapMixin, forms.ModelForm): key = forms.CharField( required=False, - help_text="If no key is provided, one will be generated automatically." + help_text=_("If no key is provided, one will be generated automatically.") ) allowed_ips = SimpleArrayField( base_field=IPNetworkFormField(), required=False, - label='Allowed IPs', - help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' - 'Example: 10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64', + label=_('Allowed IPs'), + help_text=_('Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' + 'Example: 10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64'), ) class Meta: diff --git a/netbox/users/models.py b/netbox/users/models.py index 441ed2eee..07e903569 100644 --- a/netbox/users/models.py +++ b/netbox/users/models.py @@ -10,6 +10,7 @@ from django.db import models from django.db.models.signals import post_save from django.dispatch import receiver from django.utils import timezone +from django.utils.translation import gettext as _ from netaddr import IPNetwork from ipam.fields import IPNetworkField @@ -216,7 +217,7 @@ class Token(models.Model): ) write_enabled = models.BooleanField( default=True, - help_text='Permit create/update/delete operations using this key' + help_text=_('Permit create/update/delete operations using this key') ) description = models.CharField( max_length=200, @@ -227,8 +228,8 @@ class Token(models.Model): blank=True, null=True, verbose_name='Allowed IPs', - help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' - 'Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"', + help_text=_('Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' + 'Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"'), ) def __str__(self): @@ -304,12 +305,12 @@ class ObjectPermission(models.Model): ) actions = ArrayField( base_field=models.CharField(max_length=30), - help_text="The list of actions granted by this permission" + help_text=_("The list of actions granted by this permission") ) constraints = models.JSONField( blank=True, null=True, - help_text="Queryset filter matching the applicable objects of the selected type(s)" + help_text=_("Queryset filter matching the applicable objects of the selected type(s)") ) objects = RestrictedQuerySet.as_manager() diff --git a/netbox/utilities/forms/fields/csv.py b/netbox/utilities/forms/fields/csv.py index 59765cae8..f964d0db0 100644 --- a/netbox/utilities/forms/fields/csv.py +++ b/netbox/utilities/forms/fields/csv.py @@ -5,6 +5,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.db.models import Q +from django.utils.translation import gettext as _ from utilities.choices import unpack_grouped_choices from utilities.forms.utils import parse_csv, validate_csv @@ -50,9 +51,9 @@ class CSVDataField(forms.CharField): if not self.initial: self.initial = ','.join(self.required_fields) + '\n' if not self.help_text: - self.help_text = 'Enter the list of column headers followed by one line per record to be imported, using ' \ - 'commas to separate values. Multi-line data and values containing commas may be wrapped ' \ - 'in double quotes.' + self.help_text = _('Enter the list of column headers followed by one line per record to be imported, using ' + 'commas to separate values. Multi-line data and values containing commas may be wrapped ' + 'in double quotes.') def to_python(self, value): reader = csv.reader(StringIO(value.strip())) diff --git a/netbox/utilities/forms/fields/expandable.py b/netbox/utilities/forms/fields/expandable.py index fca370c26..781de9f76 100644 --- a/netbox/utilities/forms/fields/expandable.py +++ b/netbox/utilities/forms/fields/expandable.py @@ -1,6 +1,7 @@ import re from django import forms +from django.utils.translation import gettext as _ from utilities.forms.constants import * from utilities.forms.utils import expand_alphanumeric_pattern, expand_ipaddress_pattern @@ -42,8 +43,8 @@ class ExpandableIPAddressField(forms.CharField): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.help_text: - self.help_text = 'Specify a numeric range to create multiple IPs.
'\ - 'Example: 192.0.2.[1,5,100-254]/24' + self.help_text = _('Specify a numeric range to create multiple IPs.
' + 'Example: 192.0.2.[1,5,100-254]/24') def to_python(self, value): # Hackish address family detection but it's all we have to work with diff --git a/netbox/utilities/forms/fields/fields.py b/netbox/utilities/forms/fields/fields.py index df69339e5..bb6c3f73b 100644 --- a/netbox/utilities/forms/fields/fields.py +++ b/netbox/utilities/forms/fields/fields.py @@ -4,6 +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 netaddr import AddrFormatError, EUI from utilities.forms import widgets @@ -45,7 +46,7 @@ class SlugField(forms.SlugField): slug_source: Name of the form field from which the slug value will be derived """ widget = widgets.SlugWidget - help_text = "URL-friendly unique shorthand" + help_text = _("URL-friendly unique shorthand") def __init__(self, *, slug_source='name', help_text=help_text, **kwargs): super().__init__(help_text=help_text, **kwargs) @@ -97,7 +98,7 @@ class JSONField(_JSONField): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if not self.help_text: - self.help_text = 'Enter context data in JSON format.' + self.help_text = _('Enter context data in JSON format.') self.widget.attrs['placeholder'] = '' self.widget.attrs['class'] = 'font-monospace' diff --git a/netbox/utilities/forms/forms.py b/netbox/utilities/forms/forms.py index 0569853b8..5756cf0e3 100644 --- a/netbox/utilities/forms/forms.py +++ b/netbox/utilities/forms/forms.py @@ -5,8 +5,9 @@ from io import StringIO import yaml from django import forms -from utilities.forms.utils import parse_csv +from django.utils.translation import gettext as _ +from utilities.forms.utils import parse_csv from .choices import ImportFormatChoices from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSelect @@ -103,7 +104,7 @@ class BulkRenameForm(BootstrapMixin, forms.Form): use_regex = forms.BooleanField( required=False, initial=True, - label='Use regular expressions' + label=_('Use regular expressions') ) def clean(self): @@ -145,7 +146,7 @@ class ImportForm(BootstrapMixin, forms.Form): data = forms.CharField( required=False, widget=forms.Textarea(attrs={'class': 'font-monospace'}), - help_text="Enter object data in CSV, JSON or YAML format." + help_text=_("Enter object data in CSV, JSON or YAML format.") ) data_file = forms.FileField( label="Data file", @@ -219,7 +220,7 @@ class FilterForm(BootstrapMixin, forms.Form): """ q = forms.CharField( required=False, - label='Search' + label=_('Search') ) @@ -233,7 +234,7 @@ class TableConfigForm(BootstrapMixin, forms.Form): widget=forms.SelectMultiple( attrs={'size': 10, 'class': 'form-select'} ), - label='Available Columns' + label=_('Available Columns') ) columns = forms.MultipleChoiceField( choices=[], @@ -241,7 +242,7 @@ class TableConfigForm(BootstrapMixin, forms.Form): widget=forms.SelectMultiple( attrs={'size': 10, 'class': 'form-select'} ), - label='Selected Columns' + label=_('Selected Columns') ) def __init__(self, table, *args, **kwargs): diff --git a/netbox/virtualization/filtersets.py b/netbox/virtualization/filtersets.py index 1b9c5bc78..ef33ebddc 100644 --- a/netbox/virtualization/filtersets.py +++ b/netbox/virtualization/filtersets.py @@ -1,5 +1,6 @@ import django_filters from django.db.models import Q +from django.utils.translation import gettext as _ from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup from extras.filtersets import LocalConfigContextFilterSet @@ -38,57 +39,57 @@ class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) group_id = django_filters.ModelMultipleChoiceFilter( queryset=ClusterGroup.objects.all(), - label='Parent group (ID)', + label=_('Parent group (ID)'), ) group = django_filters.ModelMultipleChoiceFilter( field_name='group__slug', queryset=ClusterGroup.objects.all(), to_field_name='slug', - label='Parent group (slug)', + label=_('Parent group (slug)'), ) type_id = django_filters.ModelMultipleChoiceFilter( queryset=ClusterType.objects.all(), - label='Cluster type (ID)', + label=_('Cluster type (ID)'), ) type = django_filters.ModelMultipleChoiceFilter( field_name='type__slug', queryset=ClusterType.objects.all(), to_field_name='slug', - label='Cluster type (slug)', + label=_('Cluster type (slug)'), ) status = django_filters.MultipleChoiceFilter( choices=ClusterStatusChoices, @@ -121,111 +122,111 @@ class VirtualMachineFilterSet( cluster_group_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group', queryset=ClusterGroup.objects.all(), - label='Cluster group (ID)', + label=_('Cluster group (ID)'), ) cluster_group = django_filters.ModelMultipleChoiceFilter( field_name='cluster__group__slug', queryset=ClusterGroup.objects.all(), to_field_name='slug', - label='Cluster group (slug)', + label=_('Cluster group (slug)'), ) cluster_type_id = django_filters.ModelMultipleChoiceFilter( field_name='cluster__type', queryset=ClusterType.objects.all(), - label='Cluster type (ID)', + label=_('Cluster type (ID)'), ) cluster_type = django_filters.ModelMultipleChoiceFilter( field_name='cluster__type__slug', queryset=ClusterType.objects.all(), to_field_name='slug', - label='Cluster type (slug)', + label=_('Cluster type (slug)'), ) cluster_id = django_filters.ModelMultipleChoiceFilter( queryset=Cluster.objects.all(), - label='Cluster (ID)', + label=_('Cluster (ID)'), ) cluster = django_filters.ModelMultipleChoiceFilter( field_name='cluster__name', queryset=Cluster.objects.all(), to_field_name='name', - label='Cluster', + label=_('Cluster'), ) device_id = django_filters.ModelMultipleChoiceFilter( queryset=Device.objects.all(), - label='Device (ID)', + label=_('Device (ID)'), ) device = django_filters.ModelMultipleChoiceFilter( field_name='device__name', queryset=Device.objects.all(), to_field_name='name', - label='Device', + label=_('Device'), ) region_id = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', - label='Region (ID)', + label=_('Region (ID)'), ) region = TreeNodeMultipleChoiceFilter( queryset=Region.objects.all(), field_name='site__region', lookup_expr='in', to_field_name='slug', - label='Region (slug)', + label=_('Region (slug)'), ) site_group_id = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', - label='Site group (ID)', + label=_('Site group (ID)'), ) site_group = TreeNodeMultipleChoiceFilter( queryset=SiteGroup.objects.all(), field_name='site__group', lookup_expr='in', to_field_name='slug', - label='Site group (slug)', + label=_('Site group (slug)'), ) site_id = django_filters.ModelMultipleChoiceFilter( queryset=Site.objects.all(), - label='Site (ID)', + label=_('Site (ID)'), ) site = django_filters.ModelMultipleChoiceFilter( field_name='site__slug', queryset=Site.objects.all(), to_field_name='slug', - label='Site (slug)', + label=_('Site (slug)'), ) name = MultiValueCharFilter( lookup_expr='iexact' ) role_id = django_filters.ModelMultipleChoiceFilter( queryset=DeviceRole.objects.all(), - label='Role (ID)', + label=_('Role (ID)'), ) role = django_filters.ModelMultipleChoiceFilter( field_name='role__slug', queryset=DeviceRole.objects.all(), to_field_name='slug', - label='Role (slug)', + label=_('Role (slug)'), ) platform_id = django_filters.ModelMultipleChoiceFilter( queryset=Platform.objects.all(), - label='Platform (ID)', + label=_('Platform (ID)'), ) platform = django_filters.ModelMultipleChoiceFilter( field_name='platform__slug', queryset=Platform.objects.all(), to_field_name='slug', - label='Platform (slug)', + label=_('Platform (slug)'), ) mac_address = MultiValueMACAddressFilter( field_name='interfaces__mac_address', - label='MAC address', + label=_('MAC address'), ) has_primary_ip = django_filters.BooleanFilter( method='_has_primary_ip', - label='Has a primary IP', + label=_('Has a primary IP'), ) class Meta: @@ -251,48 +252,48 @@ class VMInterfaceFilterSet(NetBoxModelFilterSet): cluster_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__cluster', queryset=Cluster.objects.all(), - label='Cluster (ID)', + label=_('Cluster (ID)'), ) cluster = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__cluster__name', queryset=Cluster.objects.all(), to_field_name='name', - label='Cluster', + label=_('Cluster'), ) virtual_machine_id = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine', queryset=VirtualMachine.objects.all(), - label='Virtual machine (ID)', + label=_('Virtual machine (ID)'), ) virtual_machine = django_filters.ModelMultipleChoiceFilter( field_name='virtual_machine__name', queryset=VirtualMachine.objects.all(), to_field_name='name', - label='Virtual machine', + label=_('Virtual machine'), ) parent_id = django_filters.ModelMultipleChoiceFilter( field_name='parent', queryset=VMInterface.objects.all(), - label='Parent interface (ID)', + label=_('Parent interface (ID)'), ) bridge_id = django_filters.ModelMultipleChoiceFilter( field_name='bridge', queryset=VMInterface.objects.all(), - label='Bridged interface (ID)', + label=_('Bridged interface (ID)'), ) mac_address = MultiValueMACAddressFilter( - label='MAC address', + label=_('MAC address'), ) vrf_id = django_filters.ModelMultipleChoiceFilter( field_name='vrf', queryset=VRF.objects.all(), - label='VRF', + label=_('VRF'), ) vrf = django_filters.ModelMultipleChoiceFilter( field_name='vrf__rd', queryset=VRF.objects.all(), to_field_name='rd', - label='VRF (RD)', + label=_('VRF (RD)'), ) class Meta: diff --git a/netbox/virtualization/forms/bulk_create.py b/netbox/virtualization/forms/bulk_create.py index 03997f88d..54722c7b1 100644 --- a/netbox/virtualization/forms/bulk_create.py +++ b/netbox/virtualization/forms/bulk_create.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from utilities.forms import BootstrapMixin, ExpandableNameField, form_from_model from virtualization.models import VMInterface, VirtualMachine @@ -14,7 +15,7 @@ class VirtualMachineBulkAddComponentForm(BootstrapMixin, forms.Form): widget=forms.MultipleHiddenInput() ) name = ExpandableNameField( - label='Name' + label=_('Name') ) def clean_tags(self): diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index a94b2da1c..14ae89c37 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.choices import InterfaceModeChoices from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN @@ -90,7 +91,7 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = Cluster @@ -147,15 +148,15 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): ) vcpus = forms.IntegerField( required=False, - label='vCPUs' + label=_('vCPUs') ) memory = forms.IntegerField( required=False, - label='Memory (MB)' + label=_('Memory (MB)') ) disk = forms.IntegerField( required=False, - label='Disk (GB)' + label=_('Disk (GB)') ) description = forms.CharField( max_length=200, @@ -163,7 +164,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): ) comments = CommentField( widget=SmallTextarea, - label='Comments' + label=_('Comments') ) model = VirtualMachine @@ -199,7 +200,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): required=False, min_value=INTERFACE_MTU_MIN, max_value=INTERFACE_MTU_MAX, - label='MTU' + label=_('MTU') ) description = forms.CharField( max_length=100, @@ -213,7 +214,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group' + label=_('VLAN group') ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), @@ -221,7 +222,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): query_params={ 'group_id': '$vlan_group', }, - label='Untagged VLAN' + label=_('Untagged VLAN') ) tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), @@ -229,12 +230,12 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm): query_params={ 'group_id': '$vlan_group', }, - label='Tagged VLANs' + label=_('Tagged VLANs') ) vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) model = VMInterface diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index 6fc704ae4..154c21328 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -1,5 +1,6 @@ from dcim.choices import InterfaceModeChoices from dcim.models import Device, DeviceRole, Platform, Site +from django.utils.translation import gettext as _ from ipam.models import VRF from netbox.forms import NetBoxModelCSVForm from tenancy.models import Tenant @@ -36,29 +37,29 @@ class ClusterCSVForm(NetBoxModelCSVForm): type = CSVModelChoiceField( queryset=ClusterType.objects.all(), to_field_name='name', - help_text='Type of cluster' + help_text=_('Type of cluster') ) group = CSVModelChoiceField( queryset=ClusterGroup.objects.all(), to_field_name='name', required=False, - help_text='Assigned cluster group' + help_text=_('Assigned cluster group') ) status = CSVChoiceField( choices=ClusterStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', required=False, - help_text='Assigned site' + help_text=_('Assigned site') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), to_field_name='name', required=False, - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) class Meta: @@ -69,25 +70,25 @@ class ClusterCSVForm(NetBoxModelCSVForm): class VirtualMachineCSVForm(NetBoxModelCSVForm): status = CSVChoiceField( choices=VirtualMachineStatusChoices, - help_text='Operational status' + help_text=_('Operational status') ) site = CSVModelChoiceField( queryset=Site.objects.all(), to_field_name='name', required=False, - help_text='Assigned site' + help_text=_('Assigned site') ) cluster = CSVModelChoiceField( queryset=Cluster.objects.all(), to_field_name='name', required=False, - help_text='Assigned cluster' + help_text=_('Assigned cluster') ) device = CSVModelChoiceField( queryset=Device.objects.all(), to_field_name='name', required=False, - help_text='Assigned device within cluster' + help_text=_('Assigned device within cluster') ) role = CSVModelChoiceField( queryset=DeviceRole.objects.filter( @@ -95,19 +96,19 @@ class VirtualMachineCSVForm(NetBoxModelCSVForm): ), required=False, to_field_name='name', - help_text='Functional role' + help_text=_('Functional role') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) platform = CSVModelChoiceField( queryset=Platform.objects.all(), required=False, to_field_name='name', - help_text='Assigned platform' + help_text=_('Assigned platform') ) class Meta: @@ -127,24 +128,24 @@ class VMInterfaceCSVForm(NetBoxModelCSVForm): queryset=VMInterface.objects.all(), required=False, to_field_name='name', - help_text='Parent interface' + help_text=_('Parent interface') ) bridge = CSVModelChoiceField( queryset=VMInterface.objects.all(), required=False, to_field_name='name', - help_text='Bridged interface' + help_text=_('Bridged interface') ) mode = CSVChoiceField( choices=InterfaceModeChoices, required=False, - help_text='IEEE 802.1Q operational mode (for L2 interfaces)' + help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)') ) vrf = CSVModelChoiceField( queryset=VRF.objects.all(), required=False, to_field_name='rd', - help_text='Assigned VRF' + help_text=_('Assigned VRF') ) class Meta: diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index 62fa4002e..c4fdf033a 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -160,11 +160,11 @@ class VirtualMachineFilterForm( ) mac_address = forms.CharField( required=False, - label='MAC address' + label=_('MAC address') ) has_primary_ip = forms.NullBooleanField( required=False, - label='Has a primary IP', + label=_('Has a primary IP'), widget=StaticSelect( choices=BOOLEAN_WITH_BLANK_CHOICES ) diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index 3f598d061..037af0b5c 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -1,6 +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 dcim.forms.common import InterfaceCommonForm from dcim.forms.model_forms import INTERFACE_MODE_HELP_TEXT @@ -204,7 +205,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): 'cluster_id': '$cluster', 'site_id': '$site', }, - help_text="Optionally pin this VM to a specific host device within the cluster" + help_text=_("Optionally pin this VM to a specific host device within the cluster") ) role = DynamicModelChoiceField( queryset=DeviceRole.objects.all(), @@ -240,8 +241,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): 'local_context_data', ] help_texts = { - 'local_context_data': "Local config context data overwrites all sources contexts in the final rendered " - "config context", + 'local_context_data': _("Local config context data overwrites all sources contexts in the final rendered " + "config context"), } widgets = { "status": StaticSelect(), @@ -297,7 +298,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): parent = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Parent interface', + label=_('Parent interface'), query_params={ 'virtual_machine_id': '$virtual_machine', } @@ -305,7 +306,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): bridge = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Bridged interface', + label=_('Bridged interface'), query_params={ 'virtual_machine_id': '$virtual_machine', } @@ -313,12 +314,12 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group' + label=_('VLAN group') ) untagged_vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, - label='Untagged VLAN', + label=_('Untagged VLAN'), query_params={ 'group_id': '$vlan_group', 'available_on_virtualmachine': '$virtual_machine', @@ -327,7 +328,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): tagged_vlans = DynamicModelMultipleChoiceField( queryset=VLAN.objects.all(), required=False, - label='Tagged VLANs', + label=_('Tagged VLANs'), query_params={ 'group_id': '$vlan_group', 'available_on_virtualmachine': '$virtual_machine', @@ -336,7 +337,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm): vrf = DynamicModelChoiceField( queryset=VRF.objects.all(), required=False, - label='VRF' + label=_('VRF') ) fieldsets = ( diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py index 7544327a5..be54faf9e 100644 --- a/netbox/wireless/forms/bulk_edit.py +++ b/netbox/wireless/forms/bulk_edit.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext as _ from dcim.choices import LinkStatusChoices from ipam.models import VLAN @@ -45,12 +46,12 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, - label='VLAN' + label=_('VLAN') ) ssid = forms.CharField( max_length=SSID_MAX_LENGTH, required=False, - label='SSID' + label=_('SSID') ) tenant = DynamicModelChoiceField( queryset=Tenant.objects.all(), @@ -66,7 +67,7 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): ) auth_psk = forms.CharField( required=False, - label='Pre-shared key' + label=_('Pre-shared key') ) description = forms.CharField( max_length=200, @@ -91,7 +92,7 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): ssid = forms.CharField( max_length=SSID_MAX_LENGTH, required=False, - label='SSID' + label=_('SSID') ) status = forms.ChoiceField( choices=add_blank_choice(LinkStatusChoices), @@ -111,7 +112,7 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): ) auth_psk = forms.CharField( required=False, - label='Pre-shared key' + label=_('Pre-shared key') ) description = forms.CharField( max_length=200, diff --git a/netbox/wireless/forms/bulk_import.py b/netbox/wireless/forms/bulk_import.py index 4d96f60ad..adf2a2b6c 100644 --- a/netbox/wireless/forms/bulk_import.py +++ b/netbox/wireless/forms/bulk_import.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from dcim.choices import LinkStatusChoices from dcim.models import Interface from ipam.models import VLAN @@ -19,7 +20,7 @@ class WirelessLANGroupCSVForm(NetBoxModelCSVForm): queryset=WirelessLANGroup.objects.all(), required=False, to_field_name='name', - help_text='Parent group' + help_text=_('Parent group') ) slug = SlugField() @@ -33,7 +34,7 @@ class WirelessLANCSVForm(NetBoxModelCSVForm): queryset=WirelessLANGroup.objects.all(), required=False, to_field_name='name', - help_text='Assigned group' + help_text=_('Assigned group') ) status = CSVChoiceField( choices=WirelessLANStatusChoices, @@ -43,23 +44,23 @@ class WirelessLANCSVForm(NetBoxModelCSVForm): queryset=VLAN.objects.all(), required=False, to_field_name='name', - help_text='Bridged VLAN' + help_text=_('Bridged VLAN') ) tenant = CSVModelChoiceField( queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) auth_type = CSVChoiceField( choices=WirelessAuthTypeChoices, required=False, - help_text='Authentication type' + help_text=_('Authentication type') ) auth_cipher = CSVChoiceField( choices=WirelessAuthCipherChoices, required=False, - help_text='Authentication cipher' + help_text=_('Authentication cipher') ) class Meta: @@ -73,7 +74,7 @@ class WirelessLANCSVForm(NetBoxModelCSVForm): class WirelessLinkCSVForm(NetBoxModelCSVForm): status = CSVChoiceField( choices=LinkStatusChoices, - help_text='Connection status' + help_text=_('Connection status') ) interface_a = CSVModelChoiceField( queryset=Interface.objects.all() @@ -85,17 +86,17 @@ class WirelessLinkCSVForm(NetBoxModelCSVForm): queryset=Tenant.objects.all(), required=False, to_field_name='name', - help_text='Assigned tenant' + help_text=_('Assigned tenant') ) auth_type = CSVChoiceField( choices=WirelessAuthTypeChoices, required=False, - help_text='Authentication type' + help_text=_('Authentication type') ) auth_cipher = CSVChoiceField( choices=WirelessAuthCipherChoices, required=False, - help_text='Authentication cipher' + help_text=_('Authentication cipher') ) class Meta: diff --git a/netbox/wireless/forms/filtersets.py b/netbox/wireless/forms/filtersets.py index c3e63687d..287ef779c 100644 --- a/netbox/wireless/forms/filtersets.py +++ b/netbox/wireless/forms/filtersets.py @@ -35,7 +35,7 @@ class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): ) ssid = forms.CharField( required=False, - label='SSID' + label=_('SSID') ) group_id = DynamicModelMultipleChoiceField( queryset=WirelessLANGroup.objects.all(), @@ -74,7 +74,7 @@ class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): ) ssid = forms.CharField( required=False, - label='SSID' + label=_('SSID') ) status = forms.ChoiceField( required=False, diff --git a/netbox/wireless/forms/model_forms.py b/netbox/wireless/forms/model_forms.py index e59c36696..8b45b0116 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -1,3 +1,4 @@ +from django.utils.translation import gettext as _ from dcim.models import Device, Interface, Location, Region, Site, SiteGroup from ipam.models import VLAN, VLANGroup from netbox.forms import NetBoxModelForm @@ -63,7 +64,7 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), required=False, - label='VLAN group', + label=_('VLAN group'), null_option='None', query_params={ 'site': '$site' @@ -75,7 +76,7 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): vlan = DynamicModelChoiceField( queryset=VLAN.objects.all(), required=False, - label='VLAN', + label=_('VLAN'), query_params={ 'site_id': '$site', 'group_id': '$vlan_group', @@ -107,7 +108,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): site_a = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - label='Site', + label=_('Site'), initial_params={ 'devices': '$device_a', } @@ -118,7 +119,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'site_id': '$site_a', }, required=False, - label='Location', + label=_('Location'), initial_params={ 'devices': '$device_a', } @@ -130,7 +131,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'location_id': '$location_a', }, required=False, - label='Device', + label=_('Device'), initial_params={ 'interfaces': '$interface_a' } @@ -142,12 +143,12 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'device_id': '$device_a', }, disabled_indicator='_occupied', - label='Interface' + label=_('Interface') ) site_b = DynamicModelChoiceField( queryset=Site.objects.all(), required=False, - label='Site', + label=_('Site'), initial_params={ 'devices': '$device_b', } @@ -158,7 +159,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'site_id': '$site_b', }, required=False, - label='Location', + label=_('Location'), initial_params={ 'devices': '$device_b', } @@ -170,7 +171,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'location_id': '$location_b', }, required=False, - label='Device', + label=_('Device'), initial_params={ 'interfaces': '$interface_b' } @@ -182,7 +183,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): 'device_id': '$device_b', }, disabled_indicator='_occupied', - label='Interface' + label=_('Interface') ) comments = CommentField()