From 307ea4e9eede5772d68ee76199bf6087905c6f24 Mon Sep 17 00:00:00 2001 From: Klaus-Uwe Mitterer Date: Mon, 14 Jun 2021 06:06:32 +0200 Subject: [PATCH] Internationalization preparation Creating own repo for locales --- .gitmodules | 3 +++ debian_setup.sh | 6 ++++-- frontend/fields.py | 23 +++++++++++++++++++++++ frontend/models.py | 4 +++- frontend/templatetags/startswith.py | 7 +++++++ frontend/urls.py | 3 ++- frontend/validators.py | 10 ++++++++++ frontend/views.py | 18 ++++++++++++++++-- localauth/models.py | 3 +++ locale | 1 + static/frontend/js/language.js | 10 +++++++++- templates/frontend/base.html | 9 ++++++--- urlaubsauktion/settings.py | 10 ++++++++++ 13 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 .gitmodules create mode 100644 frontend/fields.py create mode 100644 frontend/templatetags/startswith.py create mode 100644 frontend/validators.py create mode 160000 locale diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..4918be1 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "locale"] + path = locale + url = git@kumig.it:kumisystems/journeyjoker-locale.git diff --git a/debian_setup.sh b/debian_setup.sh index 24e2a53..80048f8 100644 --- a/debian_setup.sh +++ b/debian_setup.sh @@ -1,5 +1,7 @@ #!/bin/bash -apt install libpq-dev build-essential libpython3-dev postgis python3-pip python3-venv libgdal-dev wkhtmltopdf -y +apt install libpq-dev build-essential libpython3-dev postgis python3-pip python3-venv libgdal-dev wkhtmltopdf gettext -y python3 -m venv venv source venv/bin/activate -pip install -Ur requirements.txt \ No newline at end of file +pip install -Ur requirements.txt +./manage.py +./manage.py compilemessages -i venv \ No newline at end of file diff --git a/frontend/fields.py b/frontend/fields.py new file mode 100644 index 0000000..d8d92bb --- /dev/null +++ b/frontend/fields.py @@ -0,0 +1,23 @@ +from django.conf import settings +from django.db import models + +from .validators import LanguageValidator + +class LanguageField(models.CharField): + default_validators = [LanguageValidator()] + + def __init__(self, *args, **kwargs): + kwargs.setdefault("max_length", 16) + super().__init__(*args, **kwargs) + + def pre_save(self, model_instance, add): + value = getattr(model_instance, self.attname, None) + if value: + value = value.lower() + if "_" in value: + lang, country = value.split("_") + value = "_".join([lang, country.upper()]) + setattr(model_instance, self.attname, value) + return value + else: + return super().pre_save(model_instance, add) \ No newline at end of file diff --git a/frontend/models.py b/frontend/models.py index 80aede9..b29d6a6 100644 --- a/frontend/models.py +++ b/frontend/models.py @@ -5,6 +5,8 @@ from django.contrib.auth import get_user_model from localauth.models import ImageMixin +from .fields import LanguageField + from django_countries.fields import CountryField class ClassProperty(property): @@ -19,7 +21,7 @@ class Testimonial(models.Model): MaxValueValidator(5), MinValueValidator(1) ]) - language = models.CharField(max_length=12, choices=settings.LANGUAGES) + language = LanguageField() public = models.BooleanField(default=False) class InspirationRegion(models.Model): diff --git a/frontend/templatetags/startswith.py b/frontend/templatetags/startswith.py new file mode 100644 index 0000000..317227c --- /dev/null +++ b/frontend/templatetags/startswith.py @@ -0,0 +1,7 @@ +from django import template + +register = template.Library() + +@register.filter +def startswith(text, string): + return text.startswith(string) \ No newline at end of file diff --git a/frontend/urls.py b/frontend/urls.py index 07b9e94..d77f3d3 100644 --- a/frontend/urls.py +++ b/frontend/urls.py @@ -1,6 +1,6 @@ from django.urls import path, include -from .views import HomeView, DemoTemplateView, ImpressumView, PrivacyNoticeView, TOSView, InspirationsView +from .views import HomeView, DemoTemplateView, ImpressumView, PrivacyNoticeView, TOSView, InspirationsView, LanguageChoiceView app_name = "frontend" @@ -12,4 +12,5 @@ urlpatterns = [ path('privacy/', PrivacyNoticeView.as_view(), name="privacy"), path('tos/', TOSView.as_view(), name="tos"), path('inspirations/', InspirationsView.as_view(), name="inspirations"), + path('api/setlang//', LanguageChoiceView.as_view(), name="languagechoice"), ] \ No newline at end of file diff --git a/frontend/validators.py b/frontend/validators.py new file mode 100644 index 0000000..2668b72 --- /dev/null +++ b/frontend/validators.py @@ -0,0 +1,10 @@ +from django.core.exceptions import ValidationError +from django.conf import settings +from django.utils.translation import gettext_lazy as _ + +class LanguageValidator: + def __call__(self, value): + for language, _ in settings.LANGUAGES: + if language.startswith(value): + return + raise ValidationError(_("This is not a valid language code supported by this project."), code='invalid', params={'value': value}) diff --git a/frontend/views.py b/frontend/views.py index 5f4aef9..bac41af 100644 --- a/frontend/views.py +++ b/frontend/views.py @@ -1,4 +1,7 @@ -from django.views.generic import TemplateView +from django.views.generic import TemplateView, View +from django.conf import settings +from django.http.response import HttpResponse +from django.contrib import messages class HomeView(TemplateView): template_name = "frontend/index.html" @@ -19,4 +22,15 @@ class TOSView(TemplateView): template_name = "frontend/terms.html" class InspirationsView(TemplateView): - template_name = "frontend/inspirations.html" \ No newline at end of file + template_name = "frontend/inspirations.html" + +class LanguageChoiceView(View): + def get(self, request, *args, **kwargs): + response = HttpResponse() + for language, _ in settings.LANGUAGES: + if language.startswith(kwargs["code"]): + response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language) + if request.user.is_authenticated: + request.user.language = language + request.user.save() + return response \ No newline at end of file diff --git a/localauth/models.py b/localauth/models.py index d9079ef..6dcef32 100644 --- a/localauth/models.py +++ b/localauth/models.py @@ -10,6 +10,8 @@ from polymorphic.models import PolymorphicModel from .helpers import profile_to_coords, upload_path +from frontend.fields import LanguageField + class UserManager(BaseUserManager): use_in_migrations = True @@ -42,6 +44,7 @@ class User(AbstractBaseUser): date_joined = models.DateTimeField(default=timezone.now) last_login = models.DateTimeField(null=True) is_superuser = models.BooleanField(default=False) + language = LanguageField(max_length=16, default="de") objects = UserManager() diff --git a/locale b/locale new file mode 160000 index 0000000..9ec43f5 --- /dev/null +++ b/locale @@ -0,0 +1 @@ +Subproject commit 9ec43f57ecfd9f4064873527f5df6e371ee429f3 diff --git a/static/frontend/js/language.js b/static/frontend/js/language.js index f03ca79..678ec1a 100644 --- a/static/frontend/js/language.js +++ b/static/frontend/js/language.js @@ -1 +1,9 @@ -var language="DE"; \ No newline at end of file +(function($) { + + "use strict"; + + $("#language").change(function() { + $.get("/api/setlang/" + $(this).val() + "/").done(function() { document.location.reload(); }); + }); + +})(jQuery); \ No newline at end of file diff --git a/templates/frontend/base.html b/templates/frontend/base.html index daf0df6..8c15ae3 100644 --- a/templates/frontend/base.html +++ b/templates/frontend/base.html @@ -1,6 +1,7 @@ {% load static %} {% load i18n %} {% load dbsetting %} +{% load startswith %} @@ -116,9 +117,10 @@
  • - + {% get_current_language as LANGUAGE_CODE %} + +
  • @@ -358,6 +360,7 @@ + {% block "scripts" %} {% endblock %} diff --git a/urlaubsauktion/settings.py b/urlaubsauktion/settings.py index a62640b..1e380fa 100644 --- a/urlaubsauktion/settings.py +++ b/urlaubsauktion/settings.py @@ -34,6 +34,7 @@ INSTALLED_APPS = [ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -111,6 +112,15 @@ USE_L10N = True USE_TZ = True +LOCALE_PATHS = [ + BASE_DIR / "locale", +] + +LANGUAGES = [ + ('de', 'German'), + ('en', 'English') +] + # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.1/howto/static-files/