From 7fb81a0b4cc68aff293944cd6599e5715324bc6d Mon Sep 17 00:00:00 2001 From: Arthur Date: Thu, 13 Jul 2023 12:47:40 +0700 Subject: [PATCH] 13149 add gettext_lazy to forms --- netbox/extras/forms/bulk_import.py | 16 +++- netbox/extras/forms/filtersets.py | 56 +++++++++----- netbox/extras/forms/misc.py | 2 + netbox/extras/forms/model_forms.py | 118 ++++++++++++++++++----------- netbox/extras/forms/reports.py | 4 +- netbox/extras/forms/scripts.py | 4 +- 6 files changed, 131 insertions(+), 69 deletions(-) diff --git a/netbox/extras/forms/bulk_import.py b/netbox/extras/forms/bulk_import.py index b47fcba60..482d231db 100644 --- a/netbox/extras/forms/bulk_import.py +++ b/netbox/extras/forms/bulk_import.py @@ -2,7 +2,7 @@ from django import forms from django.contrib.contenttypes.models import ContentType from django.contrib.postgres.forms import SimpleArrayField from django.utils.safestring import mark_safe -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices, JournalEntryKindChoices from extras.models import * @@ -28,27 +28,32 @@ __all__ = ( class CustomFieldImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), help_text=_("One or more assigned object types") ) type = CSVChoiceField( + label=_('Type'), choices=CustomFieldTypeChoices, help_text=_('Field data type (e.g. text, integer, etc.)') ) object_type = CSVContentTypeField( + label=_('Object type'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), required=False, help_text=_("Object type (for object or multi-object fields)") ) choice_set = CSVModelChoiceField( + label=_('Choice set'), queryset=CustomFieldChoiceSet.objects.all(), to_field_name='name', required=False, help_text=_('Choice set (for selection fields)') ) ui_visibility = CSVChoiceField( + label=_('Ui visitility'), choices=CustomFieldVisibilityChoices, help_text=_('How the custom field is displayed in the user interface') ) @@ -78,6 +83,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm): class CustomLinkImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links'), help_text=_("One or more assigned object types") @@ -93,6 +99,7 @@ class CustomLinkImportForm(CSVModelForm): class ExportTemplateImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates'), help_text=_("One or more assigned object types") @@ -116,6 +123,7 @@ class ConfigTemplateImportForm(CSVModelForm): class SavedFilterImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), help_text=_("One or more assigned object types") ) @@ -129,6 +137,7 @@ class SavedFilterImportForm(CSVModelForm): class WebhookImportForm(CSVModelForm): content_types = CSVMultipleContentTypeField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks'), help_text=_("One or more assigned object types") @@ -144,7 +153,9 @@ class WebhookImportForm(CSVModelForm): class TagImportForm(CSVModelForm): - slug = SlugField() + slug = SlugField( + label=_('Slug'), + ) class Meta: model = Tag @@ -160,6 +171,7 @@ class JournalEntryImportForm(NetBoxModelImportForm): label=_('Assigned object type'), ) kind = CSVChoiceField( + label=_('Kind'), choices=JournalEntryKindChoices, help_text=_('The classification of entry') ) diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py index 26b4d9a41..f927c87cb 100644 --- a/netbox/extras/forms/filtersets.py +++ b/netbox/extras/forms/filtersets.py @@ -1,7 +1,7 @@ from django import forms from django.contrib.auth import get_user_model from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.models import DataFile, DataSource from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup @@ -37,7 +37,7 @@ __all__ = ( class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ( + (_('Attributes'), ( 'type', 'content_type_id', 'group_name', 'weight', 'required', 'choice_set_id', 'ui_visibility', 'is_cloneable', )), @@ -53,12 +53,15 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): label=_('Field type') ) group_name = forms.CharField( + label=_('Group name'), required=False ) weight = forms.IntegerField( + label=_('Weight'), required=False ) required = forms.NullBooleanField( + label=_('Required'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -75,6 +78,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm): label=_('UI visibility') ) is_cloneable = forms.NullBooleanField( + label=_('Is cloneable'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -97,22 +101,26 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): (_('Attributes'), ('content_types', 'enabled', 'new_window', 'weight')), ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('custom_links').get_query()), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) new_window = forms.NullBooleanField( + label=_('New window'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) weight = forms.IntegerField( + label=_('Weight'), required=False ) @@ -120,8 +128,8 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Data', ('data_source_id', 'data_file_id')), - ('Attributes', ('content_types', 'mime_type', 'file_extension', 'as_attachment')), + (_('Data'), ('data_source_id', 'data_file_id')), + (_('Attributes'), ('content_types', 'mime_type', 'file_extension', 'as_attachment')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -137,6 +145,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): } ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), required=False ) @@ -145,9 +154,11 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): label=_('MIME type') ) file_extension = forms.CharField( + label=_('File extension'), required=False ) as_attachment = forms.NullBooleanField( + label=_('As attachment'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -158,13 +169,15 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_type_id', 'name',)), + (_('Attributes'), ('content_type_id', 'name',)), ) content_type_id = ContentTypeChoiceField( + label=_('Content type id'), queryset=ContentType.objects.filter(FeatureQuery('custom_fields').get_query()), required=False ) name = forms.CharField( + label=_('Name'), required=False ) @@ -172,25 +185,29 @@ class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_types', 'enabled', 'shared', 'weight')), + (_('Attributes'), ('content_types', 'enabled', 'shared', 'weight')), ) content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()), required=False ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) shared = forms.NullBooleanField( + label=_('Shared'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES ) ) weight = forms.IntegerField( + label=_('Weight'), required=False ) @@ -198,8 +215,8 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm): class WebhookFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id')), - ('Attributes', ('content_type_id', 'http_method', 'enabled')), - ('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), + (_('Attributes'), ('content_type_id', 'http_method', 'enabled')), + (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), ) content_type_id = ContentTypeMultipleChoiceField( queryset=ContentType.objects.filter(FeatureQuery('webhooks').get_query()), @@ -212,6 +229,7 @@ class WebhookFilterForm(SavedFiltersMixin, FilterForm): label=_('HTTP method') ) enabled = forms.NullBooleanField( + label=_('Enabled'), required=False, widget=forms.Select( choices=BOOLEAN_WITH_BLANK_CHOICES @@ -271,11 +289,11 @@ class TagFilterForm(SavedFiltersMixin, FilterForm): class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag_id')), - ('Data', ('data_source_id', 'data_file_id')), - ('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')), - ('Device', ('device_type_id', 'platform_id', 'role_id')), - ('Cluster', ('cluster_type_id', 'cluster_group_id', 'cluster_id')), - ('Tenant', ('tenant_group_id', 'tenant_id')) + (_('Data'), ('data_source_id', 'data_file_id')), + (_('Location'), ('region_id', 'site_group_id', 'site_id', 'location_id')), + (_('Device'), ('device_type_id', 'platform_id', 'role_id')), + (_('Cluster'), ('cluster_type_id', 'cluster_group_id', 'cluster_id')), + (_('Tenant'), ('tenant_group_id', 'tenant_id')) ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -361,7 +379,7 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm): class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Data', ('data_source_id', 'data_file_id')), + (_('Data'), ('data_source_id', 'data_file_id')), ) data_source_id = DynamicModelMultipleChoiceField( queryset=DataSource.objects.all(), @@ -393,8 +411,8 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm): model = JournalEntry fieldsets = ( (None, ('q', 'filter_id', 'tag')), - ('Creation', ('created_before', 'created_after', 'created_by_id')), - ('Attributes', ('assigned_object_type_id', 'kind')) + (_('Creation'), ('created_before', 'created_after', 'created_by_id')), + (_('Attributes'), ('assigned_object_type_id', 'kind')) ) created_after = forms.DateTimeField( required=False, @@ -423,6 +441,7 @@ class JournalEntryFilterForm(NetBoxModelFilterSetForm): ) ) kind = forms.ChoiceField( + label=_('Kind'), choices=add_blank_choice(JournalEntryKindChoices), required=False ) @@ -433,8 +452,8 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): model = ObjectChange fieldsets = ( (None, ('q', 'filter_id')), - ('Time', ('time_before', 'time_after')), - ('Attributes', ('action', 'user_id', 'changed_object_type_id')), + (_('Time'), ('time_before', 'time_after')), + (_('Attributes'), ('action', 'user_id', 'changed_object_type_id')), ) time_after = forms.DateTimeField( required=False, @@ -447,6 +466,7 @@ class ObjectChangeFilterForm(SavedFiltersMixin, FilterForm): widget=DateTimePicker() ) action = forms.ChoiceField( + label=_('Action'), choices=add_blank_choice(ObjectChangeActionChoices), required=False ) diff --git a/netbox/extras/forms/misc.py b/netbox/extras/forms/misc.py index b52338e76..0fd1a889d 100644 --- a/netbox/extras/forms/misc.py +++ b/netbox/extras/forms/misc.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ __all__ = ( 'RenderMarkdownForm', @@ -10,5 +11,6 @@ class RenderMarkdownForm(forms.Form): Provides basic validation for markup to be rendered. """ text = forms.CharField( + label=_('Text'), required=False ) diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py index 428c6391b..38a1b4acd 100644 --- a/netbox/extras/forms/model_forms.py +++ b/netbox/extras/forms/model_forms.py @@ -4,7 +4,7 @@ from django import forms from django.conf import settings from django.db.models import Q from django.contrib.contenttypes.models import ContentType -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from core.forms.mixins import SyncedDataMixin from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup @@ -42,10 +42,12 @@ __all__ = ( class CustomFieldForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_fields'), ) object_type = ContentTypeChoiceField( + label=_('Object type'), queryset=ContentType.objects.all(), # TODO: Come up with a canonical way to register suitable models limit_choices_to=FeatureQuery('webhooks').get_query() | Q(app_label='auth', model__in=['user', 'group']), @@ -58,12 +60,12 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm): ) fieldsets = ( - ('Custom Field', ( + (_('Custom Field'), ( 'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'required', 'description', )), - ('Behavior', ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')), - ('Values', ('default', 'choice_set')), - ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')), + (_('Behavior'), ('search_weight', 'filter_logic', 'ui_visibility', 'weight', 'is_cloneable')), + (_('Values'), ('default', 'choice_set')), + (_('Validation'), ('validation_minimum', 'validation_maximum', 'validation_regex')), ) class Meta: @@ -100,13 +102,14 @@ class CustomFieldChoiceSetForm(BootstrapMixin, forms.ModelForm): class CustomLinkForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('custom_links') ) fieldsets = ( - ('Custom Link', ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), - ('Templates', ('link_text', 'link_url')), + (_('Custom Link'), ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')), + (_('Templates'), ('link_text', 'link_url')), ) class Meta: @@ -127,18 +130,20 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm): class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('export_templates') ) template_code = forms.CharField( + label=_('Template code'), required=False, widget=forms.Textarea(attrs={'class': 'font-monospace'}) ) fieldsets = ( - ('Export Template', ('name', 'content_types', 'description', 'template_code')), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), - ('Rendering', ('mime_type', 'file_extension', 'as_attachment')), + (_('Export Template'), ('name', 'content_types', 'description', 'template_code')), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Rendering'), ('mime_type', 'file_extension', 'as_attachment')), ) class Meta: @@ -159,7 +164,7 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local content or a data file") + raise forms.ValidationError(_("Must specify either local content or a data file")) return self.cleaned_data @@ -167,13 +172,14 @@ class ExportTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): class SavedFilterForm(BootstrapMixin, forms.ModelForm): slug = SlugField() content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all() ) parameters = JSONField() fieldsets = ( - ('Saved Filter', ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')), - ('Parameters', ('parameters',)), + (_('Saved Filter'), ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')), + (_('Parameters'), ('parameters',)), ) class Meta: @@ -192,6 +198,7 @@ class SavedFilterForm(BootstrapMixin, forms.ModelForm): class BookmarkForm(BootstrapMixin, forms.ModelForm): object_type = ContentTypeChoiceField( + label=_('Object type'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('bookmarks').get_query() ) @@ -203,29 +210,30 @@ class BookmarkForm(BootstrapMixin, forms.ModelForm): class WebhookForm(BootstrapMixin, forms.ModelForm): content_types = ContentTypeMultipleChoiceField( + label=_('Content types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('webhooks') ) fieldsets = ( - ('Webhook', ('name', 'content_types', 'enabled')), - ('Events', ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), - ('HTTP Request', ( + (_('Webhook'), ('name', 'content_types', 'enabled')), + (_('Events'), ('type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end')), + (_('HTTP Request'), ( 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret', )), - ('Conditions', ('conditions',)), - ('SSL', ('ssl_verification', 'ca_file_path')), + (_('Conditions'), ('conditions',)), + (_('SSL'), ('ssl_verification', 'ca_file_path')), ) class Meta: model = Webhook fields = '__all__' labels = { - 'type_create': 'Creations', - 'type_update': 'Updates', - 'type_delete': 'Deletions', - 'type_job_start': 'Job executions', - 'type_job_end': 'Job terminations', + 'type_create': _('Creations'), + 'type_update': _('Updates'), + 'type_delete': _('Deletions'), + 'type_job_start': _('Job executions'), + 'type_job_end': _('Job terminations'), } widgets = { 'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}), @@ -237,6 +245,7 @@ class WebhookForm(BootstrapMixin, forms.ModelForm): class TagForm(BootstrapMixin, forms.ModelForm): slug = SlugField() object_types = ContentTypeMultipleChoiceField( + label=_('Object types'), queryset=ContentType.objects.all(), limit_choices_to=FeatureQuery('tags'), required=False @@ -255,65 +264,79 @@ class TagForm(BootstrapMixin, forms.ModelForm): class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): regions = DynamicModelMultipleChoiceField( + label=_('Regions'), queryset=Region.objects.all(), required=False ) site_groups = DynamicModelMultipleChoiceField( + label=_('Site groups'), queryset=SiteGroup.objects.all(), required=False ) sites = DynamicModelMultipleChoiceField( + label=_('Sites'), queryset=Site.objects.all(), required=False ) locations = DynamicModelMultipleChoiceField( + label=_('Locations'), queryset=Location.objects.all(), required=False ) device_types = DynamicModelMultipleChoiceField( + label=_('Device types'), queryset=DeviceType.objects.all(), required=False ) roles = DynamicModelMultipleChoiceField( + label=_('Roles'), queryset=DeviceRole.objects.all(), required=False ) platforms = DynamicModelMultipleChoiceField( + label=_('Platforms'), queryset=Platform.objects.all(), required=False ) cluster_types = DynamicModelMultipleChoiceField( + label=_('Cluster types'), queryset=ClusterType.objects.all(), required=False ) cluster_groups = DynamicModelMultipleChoiceField( + label=_('Cluster groups'), queryset=ClusterGroup.objects.all(), required=False ) clusters = DynamicModelMultipleChoiceField( + label=_('Clusters'), queryset=Cluster.objects.all(), required=False ) tenant_groups = DynamicModelMultipleChoiceField( + label=_('Tenat groups'), queryset=TenantGroup.objects.all(), required=False ) tenants = DynamicModelMultipleChoiceField( + label=_('Tenants'), queryset=Tenant.objects.all(), required=False ) tags = DynamicModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False ) data = JSONField( + label=_('Data'), required=False ) fieldsets = ( - ('Config Context', ('name', 'weight', 'description', 'data', 'is_active')), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), - ('Assignment', ( + (_('Config Context'), ('name', 'weight', 'description', 'data', 'is_active')), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Assignment'), ( 'regions', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', )), @@ -345,25 +368,27 @@ class ConfigContextForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('data') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local data or a data file") + raise forms.ValidationError(_("Must specify either local data or a data file")) return self.cleaned_data class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): tags = DynamicModelMultipleChoiceField( + label=_('Tags'), queryset=Tag.objects.all(), required=False ) template_code = forms.CharField( + label=_('Template code'), required=False, widget=forms.Textarea(attrs={'class': 'font-monospace'}) ) fieldsets = ( - ('Config Template', ('name', 'description', 'environment_params', 'tags')), - ('Content', ('template_code',)), - ('Data Source', ('data_source', 'data_file', 'auto_sync_enabled')), + (_('Config Template'), ('name', 'description', 'environment_params', 'tags')), + (_('Content'), ('template_code',)), + (_('Data Source'), ('data_source', 'data_file', 'auto_sync_enabled')), ) class Meta: @@ -387,7 +412,7 @@ class ConfigTemplateForm(BootstrapMixin, SyncedDataMixin, forms.ModelForm): super().clean() if not self.cleaned_data.get('template_code') and not self.cleaned_data.get('data_file'): - raise forms.ValidationError("Must specify either local content or a data file") + raise forms.ValidationError(_("Must specify either local content or a data file")) return self.cleaned_data @@ -403,10 +428,13 @@ class ImageAttachmentForm(BootstrapMixin, forms.ModelForm): class JournalEntryForm(NetBoxModelForm): kind = forms.ChoiceField( + label=_('Kind'), choices=add_blank_choice(JournalEntryKindChoices), required=False ) - comments = CommentField() + comments = CommentField( + label=_('Comments'), + ) class Meta: model = JournalEntry @@ -445,16 +473,16 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe """ fieldsets = ( - ('Rack Elevations', ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), - ('Power', ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), - ('IPAM', ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), - ('Security', ('ALLOWED_URL_SCHEMES',)), - ('Banners', ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), - ('Pagination', ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), - ('Validation', ('CUSTOM_VALIDATORS',)), - ('User Preferences', ('DEFAULT_USER_PREFERENCES',)), - ('Miscellaneous', ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), - ('Config Revision', ('comment',)) + (_('Rack Elevations'), ('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', 'RACK_ELEVATION_DEFAULT_UNIT_WIDTH')), + (_('Power'), ('POWERFEED_DEFAULT_VOLTAGE', 'POWERFEED_DEFAULT_AMPERAGE', 'POWERFEED_DEFAULT_MAX_UTILIZATION')), + (_('IPAM'), ('ENFORCE_GLOBAL_UNIQUE', 'PREFER_IPV4')), + (_('Security'), ('ALLOWED_URL_SCHEMES',)), + (_('Banners'), ('BANNER_LOGIN', 'BANNER_MAINTENANCE', 'BANNER_TOP', 'BANNER_BOTTOM')), + (_('Pagination'), ('PAGINATE_COUNT', 'MAX_PAGE_SIZE')), + (_('Validation'), ('CUSTOM_VALIDATORS',)), + (_('User Preferences'), ('DEFAULT_USER_PREFERENCES',)), + (_('Miscellaneous'), ('MAINTENANCE_MODE', 'GRAPHQL_ENABLED', 'CHANGELOG_RETENTION', 'JOB_RETENTION', 'MAPS_URL')), + (_('Config Revision'), ('comment',)) ) class Meta: @@ -481,11 +509,11 @@ class ConfigRevisionForm(BootstrapMixin, forms.ModelForm, metaclass=ConfigFormMe help_text = self.fields[param.name].help_text if help_text: help_text += '
' # Line break - help_text += f'Current value: {value}' + help_text += _('Current value: {value}').format(value=value) if is_static: - help_text += ' (defined statically)' + help_text += _(' (defined statically)') elif value == param.default: - help_text += ' (default)' + help_text += _(' (default)') self.fields[param.name].help_text = help_text self.fields[param.name].initial = value if is_static: diff --git a/netbox/extras/forms/reports.py b/netbox/extras/forms/reports.py index 4000c01e6..0ff7d1509 100644 --- a/netbox/extras/forms/reports.py +++ b/netbox/extras/forms/reports.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import DurationChoices from utilities.forms import BootstrapMixin @@ -33,7 +33,7 @@ class ReportForm(BootstrapMixin, forms.Form): # Annotate the current system time for reference now = local_now().strftime('%Y-%m-%d %H:%M:%S') - self.fields['schedule_at'].help_text += f' (current time: {now})' + self.fields['schedule_at'].help_text += _(' (current time: {now})').format(now=now) # Remove scheduling fields if scheduling is disabled if not scheduling_enabled: diff --git a/netbox/extras/forms/scripts.py b/netbox/extras/forms/scripts.py index 19a7878e1..c555747ae 100644 --- a/netbox/extras/forms/scripts.py +++ b/netbox/extras/forms/scripts.py @@ -1,5 +1,5 @@ from django import forms -from django.utils.translation import gettext as _ +from django.utils.translation import gettext_lazy as _ from extras.choices import DurationChoices from utilities.forms import BootstrapMixin @@ -39,7 +39,7 @@ class ScriptForm(BootstrapMixin, forms.Form): # Annotate the current system time for reference now = local_now().strftime('%Y-%m-%d %H:%M:%S') - self.fields['_schedule_at'].help_text += f' (current time: {now})' + self.fields['_schedule_at'].help_text += _(' (current time: {now})').format(now=now) # Remove scheduling fields if scheduling is disabled if not scheduling_enabled: