diff --git a/netbox/account/views.py b/netbox/account/views.py index 3156b2102a6..3dbba9b296f 100644 --- a/netbox/account/views.py +++ b/netbox/account/views.py @@ -13,6 +13,7 @@ from django.urls import reverse from django.utils.decorators import method_decorator from django.utils.http import url_has_allowed_host_and_scheme, urlencode +from django.utils.translation import gettext_lazy as _ from django.views.decorators.debug import sensitive_post_parameters from django.views.generic import View from social_core.backends.utils import load_backends @@ -193,8 +194,16 @@ def post(self, request): if form.is_valid(): form.save() - messages.success(request, "Your preferences have been updated.") - return redirect('account:preferences') + messages.success(request, _("Your preferences have been updated.")) + response = redirect('account:preferences') + + # Set/clear language cookie + if language := form.cleaned_data['locale.language']: + response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language) + else: + response.delete_cookie(settings.LANGUAGE_COOKIE_NAME) + + return response return render(request, self.template_name, { 'form': form, diff --git a/netbox/netbox/preferences.py b/netbox/netbox/preferences.py index 5ef21625982..9a6fe490cee 100644 --- a/netbox/netbox/preferences.py +++ b/netbox/netbox/preferences.py @@ -1,4 +1,6 @@ +from django.conf import settings from django.utils.translation import gettext as _ + from netbox.registry import registry from users.preferences import UserPreference from utilities.paginator import EnhancedPaginator @@ -16,11 +18,18 @@ def get_page_lengths(): 'ui.colormode': UserPreference( label=_('Color mode'), choices=( - ('light', 'Light'), - ('dark', 'Dark'), + ('light', _('Light')), + ('dark', _('Dark')), ), default='light', ), + 'locale.language': UserPreference( + label=_('Language'), + choices=( + ('', _('Auto')), + *settings.LANGUAGES, + ) + ), 'pagination.per_page': UserPreference( label=_('Page length'), choices=get_page_lengths(), @@ -30,9 +39,9 @@ def get_page_lengths(): 'pagination.placement': UserPreference( label=_('Paginator placement'), choices=( - ('bottom', 'Bottom'), - ('top', 'Top'), - ('both', 'Both'), + ('bottom', _('Bottom')), + ('top', _('Top')), + ('both', _('Both')), ), description=_('Where the paginator controls will be displayed relative to a table'), default='bottom' diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 59e507d28fb..00f7c33b43c 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -13,6 +13,7 @@ from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.validators import URLValidator from django.utils.encoding import force_str +from django.utils.translation import gettext_lazy as _ try: import sentry_sdk except ModuleNotFoundError: @@ -721,6 +722,14 @@ def _setting(name, default=None): # Localization # +LANGUAGES = ( + ('en', _('English')), + ('es', _('Spanish')), + ('fr', _('French')), + ('pt', _('Portuguese')), + ('ru', _('Russian')), +) + LOCALE_PATHS = ( BASE_DIR + '/translations', ) diff --git a/netbox/users/forms/model_forms.py b/netbox/users/forms/model_forms.py index b0a43ef22d0..99320fa25c9 100644 --- a/netbox/users/forms/model_forms.py +++ b/netbox/users/forms/model_forms.py @@ -56,6 +56,7 @@ def __new__(mcs, name, bases, attrs): class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMetaclass): fieldsets = ( (_('User Interface'), ( + 'locale.language', 'pagination.per_page', 'pagination.placement', 'ui.colormode',