mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
* Allow to combine language variant with region (fixes #3947, Z#23220951) This only affects babel-based formatting (currently: currencies and phone numbers), **not** Django-based formatting (currently: date and time formats). * Remove tests where I don'T actually know whats right * Fix lookup order
This commit is contained in:
@@ -34,14 +34,13 @@
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from asgiref.local import Local
|
||||
from babel import localedata
|
||||
from django.conf import settings
|
||||
from django.utils import translation
|
||||
from django.utils.formats import date_format, number_format
|
||||
from django.utils.translation import gettext
|
||||
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
from i18nfield.fields import ( # noqa
|
||||
I18nCharField, I18nTextarea, I18nTextField, I18nTextInput,
|
||||
)
|
||||
@@ -51,6 +50,9 @@ from i18nfield.strings import LazyI18nString # noqa
|
||||
from i18nfield.utils import I18nJSONEncoder # noqa
|
||||
|
||||
|
||||
_active_region = Local()
|
||||
|
||||
|
||||
class LazyDate:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
@@ -86,6 +88,8 @@ class LazyCurrencyNumber:
|
||||
return self.__str__()
|
||||
|
||||
def __str__(self):
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
return money_filter(self.value, self.currency)
|
||||
|
||||
|
||||
@@ -105,14 +109,40 @@ ALLOWED_LANGUAGES = dict(settings.LANGUAGES)
|
||||
|
||||
|
||||
def get_babel_locale():
|
||||
babel_locale = 'en'
|
||||
# Babel, and therefore django-phonenumberfield, do not support our custom locales such das de_Informal
|
||||
if translation.get_language():
|
||||
if localedata.exists(translation.get_language()):
|
||||
babel_locale = translation.get_language()
|
||||
elif localedata.exists(translation.get_language()[:2]):
|
||||
babel_locale = translation.get_language()[:2]
|
||||
return babel_locale
|
||||
# Babel, and therefore also django-phonenumberfield, do not support our custom locales such das de_Informal
|
||||
# Also, this returns best-effort region information for number formatting etc
|
||||
current_language = translation.get_language()
|
||||
current_region = getattr(_active_region, "value", None)
|
||||
|
||||
# Babel only accepts locales that exist on the system. We try combinations in the following order:
|
||||
# language-languageversion-region
|
||||
# language-region
|
||||
# language-languageversion
|
||||
# language
|
||||
# fallback to system default
|
||||
# fallback to english
|
||||
|
||||
try_locales = []
|
||||
if "-" in current_language:
|
||||
lng_parts = current_language.split("-")
|
||||
if current_region:
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].title()}_{current_region.upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{current_region.upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].title()}")
|
||||
try_locales.append(f"{lng_parts[0]}")
|
||||
else:
|
||||
if current_region:
|
||||
try_locales.append(f"{current_language}_{current_region.upper()}")
|
||||
try_locales.append(f"{current_language}")
|
||||
|
||||
try_locales.append(settings.LANGUAGE_CODE)
|
||||
|
||||
for locale in try_locales:
|
||||
if localedata.exists(locale):
|
||||
return locale
|
||||
|
||||
return "en"
|
||||
|
||||
|
||||
def get_language_without_region(lng=None):
|
||||
@@ -132,6 +162,10 @@ def get_language_without_region(lng=None):
|
||||
return lng
|
||||
|
||||
|
||||
def set_region(region):
|
||||
_active_region.value = region
|
||||
|
||||
|
||||
@contextmanager
|
||||
def language(lng, region=None):
|
||||
"""
|
||||
@@ -143,15 +177,18 @@ def language(lng, region=None):
|
||||
formatting. If you pass a ``lng`` that already contains a region, e.g. ``pt-br``, the ``region``
|
||||
attribute will be ignored.
|
||||
"""
|
||||
_lng = translation.get_language()
|
||||
lng_before = translation.get_language()
|
||||
region_before = getattr(_active_region, "value", None)
|
||||
lng = lng or settings.LANGUAGE_CODE
|
||||
if '-' not in lng and region:
|
||||
lng += '-' + region.lower()
|
||||
translation.activate(lng)
|
||||
_active_region.value = region
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
translation.activate(_lng)
|
||||
translation.activate(lng_before)
|
||||
_active_region.value = region_before
|
||||
|
||||
|
||||
class LazyLocaleException(Exception):
|
||||
|
||||
@@ -35,7 +35,7 @@ from django.utils.translation.trans_real import (
|
||||
parse_accept_lang_header,
|
||||
)
|
||||
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
from pretix.base.i18n import get_language_without_region, set_region
|
||||
from pretix.base.settings import global_settings_object
|
||||
from pretix.multidomain.urlreverse import (
|
||||
get_event_domain, get_organizer_domain,
|
||||
@@ -92,10 +92,14 @@ class LocaleMiddleware(MiddlewareMixin):
|
||||
)
|
||||
if '-' not in language and settings_holder.settings.region:
|
||||
language += '-' + settings_holder.settings.region
|
||||
if settings_holder.settings.region:
|
||||
set_region(settings_holder.settings.region)
|
||||
else:
|
||||
gs = global_settings_object(request)
|
||||
if '-' not in language and gs.settings.region:
|
||||
language += '-' + gs.settings.region
|
||||
if gs.settings.region:
|
||||
set_region(gs.settings.region)
|
||||
|
||||
translation.activate(language)
|
||||
request.LANGUAGE_CODE = get_language_without_region()
|
||||
|
||||
@@ -26,7 +26,8 @@ from babel.numbers import format_currency
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.template.defaultfilters import floatformat
|
||||
from django.utils import translation
|
||||
|
||||
from pretix.base.i18n import get_babel_locale
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -59,13 +60,10 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
|
||||
if hide_currency:
|
||||
return floatformat(value, f"{places}g")
|
||||
|
||||
locale_parts = translation.get_language().split("-", 1)
|
||||
locale = locale_parts[0]
|
||||
if len(locale_parts) > 1 and len(locale_parts[1]) == 2:
|
||||
try:
|
||||
locale = Locale(locale_parts[0], locale_parts[1].upper())
|
||||
except UnknownLocaleError:
|
||||
pass
|
||||
try:
|
||||
locale = Locale(get_babel_locale())
|
||||
except UnknownLocaleError:
|
||||
locale = "en"
|
||||
|
||||
try:
|
||||
return format_currency(value, arg, locale=locale)
|
||||
|
||||
@@ -48,7 +48,7 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
from pretix.base.i18n import get_language_without_region, set_region
|
||||
from pretix.base.middleware import get_supported_language
|
||||
from pretix.base.models import (
|
||||
CartPosition, Customer, InvoiceAddress, ItemAddOn, OrderFee, Question,
|
||||
@@ -544,6 +544,7 @@ def iframe_entry_view_wrapper(view_func):
|
||||
region = request.event.settings.region
|
||||
if '-' not in lng and region:
|
||||
lng += '-' + region.lower()
|
||||
set_region(region)
|
||||
|
||||
# with language() is not good enough here – we really need to take the role of LocaleMiddleware and modify
|
||||
# global state, because template rendering might be happening lazily.
|
||||
|
||||
Reference in New Issue
Block a user