diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9191db7..a4bbfef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
### Added
* Optional tenant group and tenant assignments for software licenses
+* German translation for navigation, forms, tables, detail views, choices, and validation messages
### Changed
diff --git a/README.md b/README.md
index a75e532..a3c838e 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,9 @@ Lizenzen können optional einer NetBox-Mandantengruppe und einem Mandanten zugeo
Diese Variante ist für **NetBox 4.6.5** vorgesehen.
+Die Oberfläche ist auf Englisch und Deutsch verfügbar. Die Sprache richtet sich nach der in NetBox für den
+Benutzer ausgewählten Sprache.
+
## Funktionen
- Softwareprodukte und Hersteller verwalten
@@ -54,7 +57,7 @@ Die installierte Version kann anschließend geprüft werden:
/opt/netbox/venv/bin/pip show netbox-slm
```
-Für diese Variante muss dort mindestens Version `1.9.1` stehen.
+Für diese Variante muss dort mindestens Version `1.10.0` stehen.
### 3. Plugin in NetBox aktivieren
diff --git a/netbox_slm/__init__.py b/netbox_slm/__init__.py
index c6e0b71..9f6a914 100644
--- a/netbox_slm/__init__.py
+++ b/netbox_slm/__init__.py
@@ -15,15 +15,16 @@ limitations under the License.
"""
from netbox.plugins import PluginConfig
+from django.utils.translation import gettext_lazy as _
-__version__ = "1.9.1"
+__version__ = "1.10.0"
class SLMConfig(PluginConfig):
name = "netbox_slm"
- verbose_name = "Software Lifecycle Management"
+ verbose_name = _("Software Lifecycle Management")
version = __version__
- description = "Software Lifecycle Management Netbox Plugin."
+ description = _("Software Lifecycle Management NetBox Plugin.")
author = "ICTU"
author_email = "open-source-projects@ictu.nl"
base_url = "slm"
diff --git a/netbox_slm/api/serializers.py b/netbox_slm/api/serializers.py
index 23c2d9c..393ad69 100644
--- a/netbox_slm/api/serializers.py
+++ b/netbox_slm/api/serializers.py
@@ -1,5 +1,6 @@
from rest_framework import serializers
from rest_framework.serializers import SerializerMethodField, HyperlinkedIdentityField
+from django.utils.translation import gettext_lazy as _
from netbox.api.serializers import NetBoxModelSerializer
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation, SoftwareLicense
@@ -46,7 +47,7 @@ class SoftwareLicenseSerializer(NetBoxModelSerializer):
tenant = attrs.get("tenant", getattr(self.instance, "tenant", None))
if tenant_group and tenant and tenant.group_id != tenant_group.pk:
raise serializers.ValidationError(
- {"tenant": "The selected tenant does not belong to the selected tenant group."}
+ {"tenant": _("The selected tenant does not belong to the selected tenant group.")}
)
return attrs
diff --git a/netbox_slm/filtersets.py b/netbox_slm/filtersets.py
index 311e111..3fdd089 100644
--- a/netbox_slm/filtersets.py
+++ b/netbox_slm/filtersets.py
@@ -1,4 +1,5 @@
from django.db.models import Q
+from django.utils.translation import gettext_lazy as _
from django_filters import CharFilter, ModelMultipleChoiceFilter, MultipleChoiceFilter
from dcim.models import Device, Manufacturer
@@ -55,7 +56,7 @@ class SoftwareProductVersionFilterSet(NetBoxModelFilterSet):
software_product_id = ModelMultipleChoiceFilter(
queryset=SoftwareProduct.objects.all(),
- label="Software Product",
+ label=_("Software Product"),
)
class Meta:
@@ -82,12 +83,12 @@ class SoftwareProductInstallationFilterSet(NetBoxModelFilterSet):
device_id = ModelMultipleChoiceFilter(queryset=Device.objects.all())
virtualmachine_id = ModelMultipleChoiceFilter(
queryset=VirtualMachine.objects.all(),
- label="Virtual Machine",
+ label=_("Virtual Machine"),
)
cluster_id = ModelMultipleChoiceFilter(queryset=Cluster.objects.all())
software_product_id = ModelMultipleChoiceFilter(
queryset=SoftwareProduct.objects.all(),
- label="Software Product",
+ label=_("Software Product"),
)
version_id = ModelMultipleChoiceFilter(queryset=SoftwareProductVersion.objects.all())
@@ -114,17 +115,17 @@ class SoftwareLicenseFilterSet(NetBoxModelFilterSet):
name = CharFilter(lookup_expr="icontains")
description = CharFilter(lookup_expr="icontains")
type = CharFilter(lookup_expr="icontains")
- spdx_expression = CharFilter(lookup_expr="icontains", label="SPDX expression")
+ spdx_expression = CharFilter(lookup_expr="icontains", label=_("SPDX expression"))
stored_location = CharFilter(lookup_expr="icontains")
software_product_id = ModelMultipleChoiceFilter(
queryset=SoftwareProduct.objects.all(),
- label="Software Product",
+ label=_("Software Product"),
)
version_id = ModelMultipleChoiceFilter(queryset=SoftwareProductVersion.objects.all())
installation_id = ModelMultipleChoiceFilter(queryset=SoftwareProductInstallation.objects.all())
- tenant_group_id = ModelMultipleChoiceFilter(queryset=TenantGroup.objects.all(), label="Tenant Group")
- tenant_id = ModelMultipleChoiceFilter(queryset=Tenant.objects.all(), label="Tenant")
+ tenant_group_id = ModelMultipleChoiceFilter(queryset=TenantGroup.objects.all(), label=_("Tenant Group"))
+ tenant_id = ModelMultipleChoiceFilter(queryset=Tenant.objects.all(), label=_("Tenant"))
class Meta:
model = SoftwareLicense
diff --git a/netbox_slm/forms/software_license.py b/netbox_slm/forms/software_license.py
index 4ab14f4..fd48d67 100644
--- a/netbox_slm/forms/software_license.py
+++ b/netbox_slm/forms/software_license.py
@@ -1,5 +1,6 @@
from django.forms import CharField, DateField, ChoiceField, IntegerField, NullBooleanField
from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
from netbox_slm.models import (
@@ -31,9 +32,9 @@ class SoftwareLicenseForm(NetBoxModelForm):
"software_product",
"version",
"installation",
- name="Software License",
+ name=_("Software License"),
),
- FieldSet("tenant_group", "tenant", name="Tenancy"),
+ FieldSet("tenant_group", "tenant", name=_("Tenancy")),
FieldSet(
"type",
"spdx_expression",
@@ -43,12 +44,12 @@ class SoftwareLicenseForm(NetBoxModelForm):
"expiration_date",
"support",
"license_amount",
- name="License Details",
+ name=_("License Details"),
),
- FieldSet("tags", name="Tags"),
+ FieldSet("tags", name=_("Tags")),
)
- spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label="SPDX expression")
+ spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label=_("SPDX expression"))
stored_location_url = LaxURLField(required=False)
start_date = DateField(required=False, widget=DatePicker())
expiration_date = DateField(required=False, widget=DatePicker())
@@ -56,7 +57,7 @@ class SoftwareLicenseForm(NetBoxModelForm):
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=True,
- label="Software Product",
+ label=_("Software Product"),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
@@ -75,13 +76,13 @@ class SoftwareLicenseForm(NetBoxModelForm):
tenant_group = DynamicModelChoiceField(
queryset=TenantGroup.objects.all(),
required=False,
- label="Tenant Group",
+ label=_("Tenant Group"),
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False,
query_params={"group_id": "$tenant_group"},
- label="Tenant",
+ label=_("Tenant"),
)
class Meta:
@@ -132,40 +133,42 @@ class SoftwareLicenseFilterForm(NetBoxModelFilterSetForm):
name = CharField(required=False)
description = CharField(required=False)
type = CharField(required=False)
- spdx_expression = CharField(required=False, label="SPDX expression")
+ spdx_expression = CharField(required=False, label=_("SPDX expression"))
stored_location = CharField(required=False)
support = ChoiceField(required=False, choices=BOOLEAN_WITH_BLANK_CHOICES)
software_product_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
version_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProductVersion.objects.all(),
required=False,
- label="Version",
+ label=_("Version"),
)
installation_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProductInstallation.objects.all(),
required=False,
- label="Installation",
+ label=_("Installation"),
)
tenant_group_id = DynamicModelMultipleChoiceField(
queryset=TenantGroup.objects.all(),
required=False,
- label="Tenant Group",
+ label=_("Tenant Group"),
)
tenant_id = DynamicModelMultipleChoiceField(
queryset=Tenant.objects.all(),
required=False,
query_params={"group_id": "$tenant_group_id"},
- label="Tenant",
+ label=_("Tenant"),
)
class SoftwareLicenseBulkImportForm(NetBoxModelImportForm):
- support = NullBooleanField(required=False, help_text="Support (values other than 'True' and 'False' are ignored)")
+ support = NullBooleanField(
+ required=False, help_text=_("Support (values other than 'True' and 'False' are ignored)")
+ )
class Meta:
model = SoftwareLicense
@@ -226,7 +229,7 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
comments = CommentField()
type = CharField(required=False)
- spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label="SPDX expression")
+ spdx_expression = ChoiceField(required=False, choices=spdx_license_names(), label=_("SPDX expression"))
stored_location = CharField(required=False)
stored_location_url = LaxURLField(required=False)
start_date = DateField(required=False, widget=DatePicker())
@@ -237,7 +240,7 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
@@ -256,11 +259,11 @@ class SoftwareLicenseBulkEditForm(NetBoxModelBulkEditForm):
tenant_group = DynamicModelChoiceField(
queryset=TenantGroup.objects.all(),
required=False,
- label="Tenant Group",
+ label=_("Tenant Group"),
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False,
query_params={"group_id": "$tenant_group"},
- label="Tenant",
+ label=_("Tenant"),
)
diff --git a/netbox_slm/forms/software_product.py b/netbox_slm/forms/software_product.py
index 1dc79f5..022772e 100644
--- a/netbox_slm/forms/software_product.py
+++ b/netbox_slm/forms/software_product.py
@@ -1,4 +1,5 @@
from django.forms import CharField
+from django.utils.translation import gettext_lazy as _
from dcim.models import Manufacturer
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
@@ -46,7 +47,7 @@ class SoftwareProductFilterForm(NetBoxModelFilterSetForm):
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
required=False,
- label="Manufacturer",
+ label=_("Manufacturer"),
)
diff --git a/netbox_slm/forms/software_product_installation.py b/netbox_slm/forms/software_product_installation.py
index b648f7f..9bdcb52 100644
--- a/netbox_slm/forms/software_product_installation.py
+++ b/netbox_slm/forms/software_product_installation.py
@@ -1,5 +1,6 @@
from django.forms import ValidationError
from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
from dcim.models import Device
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
@@ -22,13 +23,13 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
virtualmachine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
- label="Virtual Machine",
+ label=_("Virtual Machine"),
)
cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=True,
- label="Software Product",
+ label=_("Software Product"),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
@@ -54,8 +55,8 @@ class SoftwareProductInstallationForm(NetBoxModelForm):
software_product = self.cleaned_data["software_product"]
if version not in software_product.softwareproductversion_set.all():
raise ValidationError(
- f"Version '{version}' doesn't exist on {software_product}, make sure you've "
- f"selected a compatible version or first select the software product."
+ _("Version '%(version)s' does not belong to %(product)s. Select a compatible version.")
+ % {"version": version, "product": software_product}
)
return version
@@ -73,27 +74,27 @@ class SoftwareProductInstallationFilterForm(NetBoxModelFilterSetForm):
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
- label="Device",
+ label=_("Device"),
)
virtualmachine_id = DynamicModelMultipleChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
- label="Virtual Machine",
+ label=_("Virtual Machine"),
)
cluster_id = DynamicModelMultipleChoiceField(
queryset=Cluster.objects.all(),
required=False,
- label="Cluster",
+ label=_("Cluster"),
)
software_product_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
version_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProductVersion.objects.all(),
required=False,
- label="Version",
+ label=_("Version"),
)
@@ -122,13 +123,13 @@ class SoftwareProductInstallationBulkEditForm(NetBoxModelBulkEditForm):
virtualmachine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(),
required=False,
- label="Virtual Machine",
+ label=_("Virtual Machine"),
)
cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
version = DynamicModelChoiceField(
queryset=SoftwareProductVersion.objects.all(),
diff --git a/netbox_slm/forms/software_product_version.py b/netbox_slm/forms/software_product_version.py
index 3510be3..32f2ecf 100644
--- a/netbox_slm/forms/software_product_version.py
+++ b/netbox_slm/forms/software_product_version.py
@@ -1,5 +1,6 @@
from django.forms import DateField, CharField, MultipleChoiceField
from django.urls import reverse_lazy
+from django.utils.translation import gettext_lazy as _
from dcim.models import Manufacturer
from netbox.forms import NetBoxModelForm, NetBoxModelFilterSetForm, NetBoxModelImportForm, NetBoxModelBulkEditForm
@@ -23,7 +24,7 @@ class SoftwareProductVersionForm(NetBoxModelForm):
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=True,
- label="Software Product",
+ label=_("Software Product"),
widget=APISelect(attrs={"data-url": reverse_lazy("plugins-api:netbox_slm-api:softwareproduct-list")}),
)
@@ -64,17 +65,19 @@ class SoftwareProductVersionFilterForm(NetBoxModelFilterSetForm):
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
required=False,
- label="Manufacturer",
+ label=_("Manufacturer"),
)
software_product_id = DynamicModelMultipleChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
class SoftwareProductVersionBulkImportForm(NetBoxModelImportForm):
- release_type = CharField(help_text=f"Release type (possible values: {SoftwareReleaseTypes.values})")
+ release_type = CharField(
+ help_text=_("Release type (possible values: %(values)s)") % {"values": SoftwareReleaseTypes.values}
+ )
class Meta:
model = SoftwareProductVersion
@@ -122,5 +125,5 @@ class SoftwareProductVersionBulkEditForm(NetBoxModelBulkEditForm):
software_product = DynamicModelChoiceField(
queryset=SoftwareProduct.objects.all(),
required=False,
- label="Software Product",
+ label=_("Software Product"),
)
diff --git a/netbox_slm/locale/de/LC_MESSAGES/django.mo b/netbox_slm/locale/de/LC_MESSAGES/django.mo
new file mode 100644
index 0000000..8303efd
Binary files /dev/null and b/netbox_slm/locale/de/LC_MESSAGES/django.mo differ
diff --git a/netbox_slm/locale/de/LC_MESSAGES/django.po b/netbox_slm/locale/de/LC_MESSAGES/django.po
new file mode 100644
index 0000000..7207611
--- /dev/null
+++ b/netbox_slm/locale/de/LC_MESSAGES/django.po
@@ -0,0 +1,263 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: netbox-slm 1.9.1\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgid "Add"
+msgstr "Hinzufügen"
+
+msgid "Import"
+msgstr "Importieren"
+
+msgid "Software Lifecycle"
+msgstr "Software-Lebenszyklus"
+
+msgid "Software Products"
+msgstr "Softwareprodukte"
+
+msgid "Software Product"
+msgstr "Softwareprodukt"
+
+msgid "Software Product Version"
+msgstr "Softwareproduktversion"
+
+msgid "Software Product Installation"
+msgstr "Softwareproduktinstallation"
+
+msgid "Software License"
+msgstr "Softwarelizenz"
+
+msgid "License Details"
+msgstr "Lizenzdetails"
+
+msgid "Versions"
+msgstr "Versionen"
+
+msgid "Version"
+msgstr "Version"
+
+msgid "Installations"
+msgstr "Installationen"
+
+msgid "Installation"
+msgstr "Installation"
+
+msgid "Add an installation"
+msgstr "Installation hinzufügen"
+
+msgid "Licenses"
+msgstr "Lizenzen"
+
+msgid "Tenancy"
+msgstr "Mandantenzuordnung"
+
+msgid "Tenant Group"
+msgstr "Mandantengruppe"
+
+msgid "Tenant"
+msgstr "Mandant"
+
+msgid "Manufacturer"
+msgstr "Hersteller"
+
+msgid "Device"
+msgstr "Gerät"
+
+msgid "Virtual Machine"
+msgstr "Virtuelle Maschine"
+
+msgid "Cluster"
+msgstr "Cluster"
+
+msgid "Name"
+msgstr "Name"
+
+msgid "Description"
+msgstr "Beschreibung"
+
+msgid "Type"
+msgstr "Typ"
+
+msgid "SPDX expression"
+msgstr "SPDX-Ausdruck"
+
+msgid "Stored location"
+msgstr "Ablageort"
+
+msgid "Start date"
+msgstr "Startdatum"
+
+msgid "Expiration date"
+msgstr "Ablaufdatum"
+
+msgid "Support"
+msgstr "Support"
+
+msgid "License amount"
+msgstr "Lizenzanzahl"
+
+msgid "Release date"
+msgstr "Veröffentlichungsdatum"
+
+msgid "Documentation URL"
+msgstr "Dokumentations-URL"
+
+msgid "End of support"
+msgstr "Supportende"
+
+msgid "Filename"
+msgstr "Dateiname"
+
+msgid "File checksum"
+msgstr "Dateiprüfsumme"
+
+msgid "Release type"
+msgstr "Veröffentlichungstyp"
+
+msgid "Release candidate"
+msgstr "Veröffentlichungskandidat"
+
+msgid "Stable release"
+msgstr "Stabile Veröffentlichung"
+
+msgid "Alpha"
+msgstr "Alpha"
+
+msgid "Beta"
+msgstr "Beta"
+
+msgid "Tags"
+msgstr "Tags"
+
+msgid "None"
+msgstr "Keine"
+
+msgid "Link"
+msgstr "Link"
+
+msgid "Support (values other than 'True' and 'False' are ignored)"
+msgstr "Support (andere Werte als ‚True‘ und ‚False‘ werden ignoriert)"
+
+msgid "Release type (possible values: %(values)s)"
+msgstr "Veröffentlichungstyp (mögliche Werte: %(values)s)"
+
+msgid "Version '%(version)s' does not belong to %(product)s. Select a compatible version."
+msgstr "Version ‚%(version)s‘ gehört nicht zu %(product)s. Wähle eine kompatible Version aus."
+
+msgid "Installation requires exactly one platform destination."
+msgstr "Eine Installation benötigt genau ein Plattformziel."
+
+msgid "%(value)s is not a known SPDX license expression"
+msgstr "%(value)s ist kein bekannter SPDX-Lizenzausdruck"
+
+msgid "The selected tenant does not belong to the selected tenant group."
+msgstr "Der ausgewählte Mandant gehört nicht zur ausgewählten Mandantengruppe."
+
+msgid "Software Lifecycle Management"
+msgstr "Software-Lebenszyklusverwaltung"
+
+msgid "Software Lifecycle Management NetBox Plugin."
+msgstr "NetBox-Plugin zur Verwaltung des Software-Lebenszyklus."
+
+msgid "name"
+msgstr "Name"
+
+msgid "comments"
+msgstr "Kommentare"
+
+msgid "description"
+msgstr "Beschreibung"
+
+msgid "manufacturer"
+msgstr "Hersteller"
+
+msgid "software product"
+msgstr "Softwareprodukt"
+
+msgid "software products"
+msgstr "Softwareprodukte"
+
+msgid "release date"
+msgstr "Veröffentlichungsdatum"
+
+msgid "documentation URL"
+msgstr "Dokumentations-URL"
+
+msgid "end of support"
+msgstr "Supportende"
+
+msgid "filename"
+msgstr "Dateiname"
+
+msgid "file checksum"
+msgstr "Dateiprüfsumme"
+
+msgid "file link"
+msgstr "Dateilink"
+
+msgid "release type"
+msgstr "Veröffentlichungstyp"
+
+msgid "software product version"
+msgstr "Softwareproduktversion"
+
+msgid "software product versions"
+msgstr "Softwareproduktversionen"
+
+msgid "device"
+msgstr "Gerät"
+
+msgid "virtual machine"
+msgstr "Virtuelle Maschine"
+
+msgid "cluster"
+msgstr "Cluster"
+
+msgid "version"
+msgstr "Version"
+
+msgid "software product installation"
+msgstr "Softwareproduktinstallation"
+
+msgid "software product installations"
+msgstr "Softwareproduktinstallationen"
+
+msgid "type"
+msgstr "Typ"
+
+msgid "stored location"
+msgstr "Ablageort"
+
+msgid "stored location URL"
+msgstr "Ablageort-URL"
+
+msgid "start date"
+msgstr "Startdatum"
+
+msgid "expiration date"
+msgstr "Ablaufdatum"
+
+msgid "support"
+msgstr "Support"
+
+msgid "license amount"
+msgstr "Lizenzanzahl"
+
+msgid "installation"
+msgstr "Installation"
+
+msgid "tenant group"
+msgstr "Mandantengruppe"
+
+msgid "tenant"
+msgstr "Mandant"
+
+msgid "software license"
+msgstr "Softwarelizenz"
+
+msgid "software licenses"
+msgstr "Softwarelizenzen"
diff --git a/netbox_slm/models.py b/netbox_slm/models.py
index 466fb86..d6ebb52 100644
--- a/netbox_slm/models.py
+++ b/netbox_slm/models.py
@@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.html import format_html
+from django.utils.translation import gettext_lazy as _
from license_expression import Licensing, get_spdx_licensing
from netbox.models import NetBoxModel
@@ -21,14 +22,20 @@ class LaxURLField(models.URLField):
class SoftwareProduct(NetBoxModel):
- name = models.CharField(max_length=128)
- comments = models.TextField(blank=True)
+ name = models.CharField(_("name"), max_length=128)
+ comments = models.TextField(_("comments"), blank=True)
- description = models.CharField(max_length=255, null=True, blank=True)
- manufacturer = models.ForeignKey(to="dcim.Manufacturer", on_delete=models.PROTECT, null=True, blank=True)
+ description = models.CharField(_("description"), max_length=255, null=True, blank=True)
+ manufacturer = models.ForeignKey(
+ to="dcim.Manufacturer", verbose_name=_("manufacturer"), on_delete=models.PROTECT, null=True, blank=True
+ )
objects = RestrictedQuerySet.as_manager()
+ class Meta:
+ verbose_name = _("software product")
+ verbose_name_plural = _("software products")
+
def __str__(self):
return self.name
@@ -44,25 +51,26 @@ class SoftwareProduct(NetBoxModel):
class SoftwareReleaseTypes(models.TextChoices):
- ALPHA = "A", "Alpha"
- BETA = "B", "Beta"
- RELEASE_CANDIDATE = "RC", "Release candidate"
- STABLE = "S", "Stable release"
+ ALPHA = "A", _("Alpha")
+ BETA = "B", _("Beta")
+ RELEASE_CANDIDATE = "RC", _("Release candidate")
+ STABLE = "S", _("Stable release")
class SoftwareProductVersion(NetBoxModel):
- name = models.CharField(max_length=64)
- comments = models.TextField(blank=True)
+ name = models.CharField(_("name"), max_length=64)
+ comments = models.TextField(_("comments"), blank=True)
- description = models.CharField(max_length=255, null=True, blank=True)
- release_date = models.DateField(null=True, blank=True)
- documentation_url = LaxURLField(max_length=1024, null=True, blank=True)
- end_of_support = models.DateField(null=True, blank=True)
- filename = models.CharField(max_length=64, null=True, blank=True)
- file_checksum = models.CharField(max_length=128, null=True, blank=True)
- file_link = LaxURLField(max_length=1024, null=True, blank=True)
+ description = models.CharField(_("description"), max_length=255, null=True, blank=True)
+ release_date = models.DateField(_("release date"), null=True, blank=True)
+ documentation_url = LaxURLField(_("documentation URL"), max_length=1024, null=True, blank=True)
+ end_of_support = models.DateField(_("end of support"), null=True, blank=True)
+ filename = models.CharField(_("filename"), max_length=64, null=True, blank=True)
+ file_checksum = models.CharField(_("file checksum"), max_length=128, null=True, blank=True)
+ file_link = LaxURLField(_("file link"), max_length=1024, null=True, blank=True)
release_type = models.CharField(
+ _("release type"),
max_length=3,
choices=SoftwareReleaseTypes.choices,
default=SoftwareReleaseTypes.STABLE,
@@ -70,11 +78,16 @@ class SoftwareProductVersion(NetBoxModel):
software_product = models.ForeignKey(
to="netbox_slm.SoftwareProduct",
+ verbose_name=_("software product"),
on_delete=models.PROTECT,
)
objects = RestrictedQuerySet.as_manager()
+ class Meta:
+ verbose_name = _("software product version")
+ verbose_name_plural = _("software product versions")
+
def __str__(self):
return self.name
@@ -88,15 +101,27 @@ class SoftwareProductVersion(NetBoxModel):
class SoftwareProductInstallation(NetBoxModel):
- comments = models.TextField(blank=True)
+ comments = models.TextField(_("comments"), blank=True)
- device = models.ForeignKey(to="dcim.Device", on_delete=models.PROTECT, null=True, blank=True)
- virtualmachine = models.ForeignKey(
- to="virtualization.VirtualMachine", on_delete=models.PROTECT, null=True, blank=True
+ device = models.ForeignKey(
+ to="dcim.Device", verbose_name=_("device"), on_delete=models.PROTECT, null=True, blank=True
+ )
+ virtualmachine = models.ForeignKey(
+ to="virtualization.VirtualMachine",
+ verbose_name=_("virtual machine"),
+ on_delete=models.PROTECT,
+ null=True,
+ blank=True,
+ )
+ cluster = models.ForeignKey(
+ to="virtualization.Cluster", verbose_name=_("cluster"), on_delete=models.PROTECT, null=True, blank=True
+ )
+ software_product = models.ForeignKey(
+ to="netbox_slm.SoftwareProduct", verbose_name=_("software product"), on_delete=models.PROTECT
+ )
+ version = models.ForeignKey(
+ to="netbox_slm.SoftwareProductVersion", verbose_name=_("version"), on_delete=models.PROTECT
)
- cluster = models.ForeignKey(to="virtualization.Cluster", on_delete=models.PROTECT, null=True, blank=True)
- software_product = models.ForeignKey(to="netbox_slm.SoftwareProduct", on_delete=models.PROTECT)
- version = models.ForeignKey(to="netbox_slm.SoftwareProductVersion", on_delete=models.PROTECT)
objects = RestrictedQuerySet.as_manager()
@@ -104,6 +129,8 @@ class SoftwareProductInstallation(NetBoxModel):
return f"{self.pk} ({self.platform})"
class Meta:
+ verbose_name = _("software product installation")
+ verbose_name_plural = _("software product installations")
constraints = [
models.CheckConstraint(
name="%(app_label)s_%(class)s_platform",
@@ -112,7 +139,7 @@ class SoftwareProductInstallation(NetBoxModel):
| models.Q(device__isnull=True, virtualmachine__isnull=False, cluster__isnull=True)
| models.Q(device__isnull=True, virtualmachine__isnull=True, cluster__isnull=False)
),
- violation_error_message="Installation requires exactly one platform destination.",
+ violation_error_message=_("Installation requires exactly one platform destination."),
)
]
@@ -141,30 +168,45 @@ def spdx_license_names():
def validate_spdx_expression(value):
expression_info = spdx_licensing.validate(value)
if expression_info.errors:
- raise ValidationError(f"{value} is not a known SPDX license expression")
+ raise ValidationError(_("%(value)s is not a known SPDX license expression") % {"value": value})
class SoftwareLicense(NetBoxModel):
- name = models.CharField(max_length=128)
- comments = models.TextField(blank=True)
+ name = models.CharField(_("name"), max_length=128)
+ comments = models.TextField(_("comments"), blank=True)
- description = models.CharField(max_length=255, null=True, blank=True)
- type = models.CharField(max_length=128)
- spdx_expression = models.CharField(max_length=64, null=True, blank=True, validators=[validate_spdx_expression])
- stored_location = models.CharField(max_length=255, null=True, blank=True)
- stored_location_url = LaxURLField(max_length=1024, null=True, blank=True)
- start_date = models.DateField(null=True, blank=True)
- expiration_date = models.DateField(null=True, blank=True)
- support = models.BooleanField(default=None, null=True, blank=True)
- license_amount = models.PositiveIntegerField(default=None, null=True, blank=True)
+ description = models.CharField(_("description"), max_length=255, null=True, blank=True)
+ type = models.CharField(_("type"), max_length=128)
+ spdx_expression = models.CharField(
+ _("SPDX expression"), max_length=64, null=True, blank=True, validators=[validate_spdx_expression]
+ )
+ stored_location = models.CharField(_("stored location"), max_length=255, null=True, blank=True)
+ stored_location_url = LaxURLField(_("stored location URL"), max_length=1024, null=True, blank=True)
+ start_date = models.DateField(_("start date"), null=True, blank=True)
+ expiration_date = models.DateField(_("expiration date"), null=True, blank=True)
+ support = models.BooleanField(_("support"), default=None, null=True, blank=True)
+ license_amount = models.PositiveIntegerField(_("license amount"), default=None, null=True, blank=True)
- software_product = models.ForeignKey(to="netbox_slm.SoftwareProduct", on_delete=models.PROTECT)
- version = models.ForeignKey(to="netbox_slm.SoftwareProductVersion", on_delete=models.PROTECT, null=True, blank=True)
+ software_product = models.ForeignKey(
+ to="netbox_slm.SoftwareProduct", verbose_name=_("software product"), on_delete=models.PROTECT
+ )
+ version = models.ForeignKey(
+ to="netbox_slm.SoftwareProductVersion",
+ verbose_name=_("version"),
+ on_delete=models.PROTECT,
+ null=True,
+ blank=True,
+ )
installation = models.ForeignKey(
- to="netbox_slm.SoftwareProductInstallation", on_delete=models.SET_NULL, null=True, blank=True
+ to="netbox_slm.SoftwareProductInstallation",
+ verbose_name=_("installation"),
+ on_delete=models.SET_NULL,
+ null=True,
+ blank=True,
)
tenant_group = models.ForeignKey(
to="tenancy.TenantGroup",
+ verbose_name=_("tenant group"),
on_delete=models.PROTECT,
null=True,
blank=True,
@@ -172,6 +214,7 @@ class SoftwareLicense(NetBoxModel):
)
tenant = models.ForeignKey(
to="tenancy.Tenant",
+ verbose_name=_("tenant"),
on_delete=models.PROTECT,
null=True,
blank=True,
@@ -180,6 +223,10 @@ class SoftwareLicense(NetBoxModel):
objects = RestrictedQuerySet.as_manager()
+ class Meta:
+ verbose_name = _("software license")
+ verbose_name_plural = _("software licenses")
+
def __str__(self):
return self.name
@@ -189,10 +236,12 @@ class SoftwareLicense(NetBoxModel):
def clean(self):
super().clean()
if self.tenant_group and self.tenant and self.tenant.group_id != self.tenant_group_id:
- raise ValidationError({"tenant": "The selected tenant does not belong to the selected tenant group."})
+ raise ValidationError(
+ {"tenant": _("The selected tenant does not belong to the selected tenant group.")}
+ )
@property
def stored_location_txt(self):
if self.stored_location_url and not self.stored_location:
- return "Link"
+ return _("Link")
return self.stored_location
diff --git a/netbox_slm/navigation.py b/netbox_slm/navigation.py
index 6ce7825..4e29655 100644
--- a/netbox_slm/navigation.py
+++ b/netbox_slm/navigation.py
@@ -1,21 +1,22 @@
from netbox.plugins import PluginMenuButton, PluginMenuItem, PluginMenu, get_plugin_config
+from django.utils.translation import gettext_lazy as _
from . import SLMConfig
slm_items = (
PluginMenuItem(
link="plugins:netbox_slm:softwareproduct_list",
- link_text="Software Products",
+ link_text=_("Software Products"),
permissions=["netbox_slm.add_softwareproduct"],
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproduct_add",
- "Add",
+ _("Add"),
"mdi mdi-plus-thick",
permissions=["netbox_slm.add_softwareproduct"],
),
PluginMenuButton(
"plugins:netbox_slm:softwareproduct_bulk_import",
- "Import",
+ _("Import"),
"mdi mdi-upload",
permissions=["netbox_slm.import_softwareproduct"],
),
@@ -23,18 +24,18 @@ slm_items = (
),
PluginMenuItem(
link="plugins:netbox_slm:softwareproductversion_list",
- link_text="Versions",
+ link_text=_("Versions"),
permissions=["netbox_slm.add_softwareproductversion"],
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproductversion_add",
- "Add",
+ _("Add"),
"mdi mdi-plus-thick",
permissions=["netbox_slm.add_softwareproductversion"],
),
PluginMenuButton(
"plugins:netbox_slm:softwareproductversion_bulk_import",
- "Import",
+ _("Import"),
"mdi mdi-upload",
permissions=["netbox_slm.import_softwareproductversion"],
),
@@ -42,18 +43,18 @@ slm_items = (
),
PluginMenuItem(
link="plugins:netbox_slm:softwareproductinstallation_list",
- link_text="Installations",
+ link_text=_("Installations"),
permissions=["netbox_slm.add_softwareproductinstallation"],
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwareproductinstallation_add",
- "Add",
+ _("Add"),
"mdi mdi-plus-thick",
permissions=["netbox_slm.add_softwareproductinstallation"],
),
PluginMenuButton(
"plugins:netbox_slm:softwareproductinstallation_bulk_import",
- "Import",
+ _("Import"),
"mdi mdi-upload",
permissions=["netbox_slm.import_softwareproductinstallation"],
),
@@ -61,18 +62,18 @@ slm_items = (
),
PluginMenuItem(
link="plugins:netbox_slm:softwarelicense_list",
- link_text="Licenses",
+ link_text=_("Licenses"),
permissions=["netbox_slm.add_softwarelicense"],
buttons=(
PluginMenuButton(
"plugins:netbox_slm:softwarelicense_add",
- "Add",
+ _("Add"),
"mdi mdi-plus-thick",
permissions=["netbox_slm.add_softwarelicense"],
),
PluginMenuButton(
"plugins:netbox_slm:softwarelicense_bulk_import",
- "Import",
+ _("Import"),
"mdi mdi-upload",
permissions=["netbox_slm.import_softwarelicense"],
),
@@ -82,7 +83,7 @@ slm_items = (
if get_plugin_config("netbox_slm", "top_level_menu"):
menu = PluginMenu(
- label="Software Lifecycle",
+ label=_("Software Lifecycle"),
groups=((SLMConfig.verbose_name, slm_items),),
icon_class="mdi mdi-content-save",
)
diff --git a/netbox_slm/tables.py b/netbox_slm/tables.py
index cb04259..0bd5667 100644
--- a/netbox_slm/tables.py
+++ b/netbox_slm/tables.py
@@ -1,5 +1,6 @@
import django_tables2 as tables
from django.db.models import Count, F, Value
+from django.utils.translation import gettext_lazy as _
from netbox.tables import NetBoxTable, ToggleColumn, columns
from netbox_slm.models import SoftwareProduct, SoftwareProductVersion, SoftwareProductInstallation, SoftwareLicense
@@ -45,7 +46,7 @@ class SoftwareProductVersionTable(NetBoxTable):
pk = ToggleColumn()
name = tables.LinkColumn()
- software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
+ software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
installations = tables.Column(accessor="get_installation_count")
@@ -89,7 +90,7 @@ class SoftwareProductInstallationTable(NetBoxTable):
platform = tables.Column(accessor="platform", linkify=True)
type = tables.Column(accessor="render_type")
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
- software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
+ software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
version = tables.Column(accessor="version", linkify=True)
tags = columns.TagColumn(url_name="plugins:netbox_slm:softwareproductinstallation_list")
@@ -137,14 +138,14 @@ class SoftwareLicenseTable(NetBoxTable):
name = tables.LinkColumn()
type = tables.Column()
- spdx_expression = tables.Column(verbose_name="SPDX expression")
+ spdx_expression = tables.Column(verbose_name=_("SPDX expression"))
stored_location = tables.Column(accessor="stored_location_txt", linkify=lambda record: record.stored_location_url)
manufacturer = tables.Column(accessor="software_product__manufacturer", linkify=True)
- software_product = tables.Column(accessor="software_product", verbose_name="Software Product", linkify=True)
+ software_product = tables.Column(accessor="software_product", verbose_name=_("Software Product"), linkify=True)
version = tables.Column(accessor="version", linkify=True)
installation = tables.Column(accessor="installation", linkify=True)
- tenant_group = tables.Column(accessor="tenant_group", verbose_name="Tenant Group", linkify=True)
+ tenant_group = tables.Column(accessor="tenant_group", verbose_name=_("Tenant Group"), linkify=True)
tenant = tables.Column(accessor="tenant", linkify=True)
tags = columns.TagColumn(url_name="plugins:netbox_slm:softwarelicense_list")
diff --git a/netbox_slm/templates/netbox_slm/installations_card_include.html b/netbox_slm/templates/netbox_slm/installations_card_include.html
index 896c995..3b7d09a 100644
--- a/netbox_slm/templates/netbox_slm/installations_card_include.html
+++ b/netbox_slm/templates/netbox_slm/installations_card_include.html
@@ -1,12 +1,13 @@
{% load helpers %}
+{% load i18n %}