Unicode-aware sorting of phone prefixes (#2523)

This commit is contained in:
Raphael Michel
2022-03-14 15:24:59 +01:00
committed by GitHub
parent 06b0ef906a
commit 959b076b52
2 changed files with 50 additions and 15 deletions

View File

@@ -41,7 +41,6 @@ from io import BytesIO
import dateutil.parser
import pycountry
import pytz
from babel import Locale
from django import forms
from django.conf import settings
from django.contrib import messages
@@ -52,7 +51,6 @@ from django.core.validators import (
)
from django.db.models import QuerySet
from django.forms import Select, widgets
from django.utils import translation
from django.utils.formats import date_format
from django.utils.html import escape
from django.utils.safestring import mark_safe
@@ -87,7 +85,9 @@ from pretix.base.templatetags.rich_text import rich_text
from pretix.control.forms import (
ExtFileField, ExtValidationMixin, SizeValidationMixin, SplitDateTimeField,
)
from pretix.helpers.countries import CachedCountries
from pretix.helpers.countries import (
CachedCountries, get_phone_prefixes_sorted_and_localized,
)
from pretix.helpers.escapejson import escapejson_attr
from pretix.helpers.i18n import get_format_without_seconds
from pretix.presale.signals import question_form_fields
@@ -264,17 +264,14 @@ class WrappedPhonePrefixSelect(Select):
def __init__(self, initial=None):
choices = [("", "---------")]
language = get_babel_locale() # changed from default implementation that used the django locale
locale = Locale(translation.to_locale(language))
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
prefix = "+%d" % prefix
if initial and initial in values:
self.initial = prefix
for country_code in values:
country_name = locale.territories.get(country_code)
if country_name:
choices.append((prefix, "{} {}".format(country_name, prefix)))
super().__init__(choices=sorted(choices, key=lambda item: item[1]), attrs={'aria-label': pgettext_lazy('phonenumber', 'International area code')})
if initial:
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
if initial in values:
self.initial = "+%d" % prefix
break
choices += get_phone_prefixes_sorted_and_localized()
super().__init__(choices=choices, attrs={'aria-label': pgettext_lazy('phonenumber', 'International area code')})
def render(self, name, value, *args, **kwargs):
return super().render(name, value or self.initial, *args, **kwargs)

View File

@@ -19,11 +19,17 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import pyuca
from babel.core import Locale
from django.core.cache import cache
from django.utils import translation
from django_countries import Countries
from django_countries.fields import CountryField
from phonenumbers.data import _COUNTRY_CODE_TO_REGION_CODE
from pretix.base.i18n import get_language_without_region
from pretix.base.i18n import get_babel_locale, get_language_without_region
_collator = pyuca.Collator()
class CachedCountries(Countries):
@@ -83,3 +89,35 @@ class FastCountryField(CountryField):
*self._check_multiple(),
*self._check_max_length_attribute(**kwargs),
]
_cached_phone_prefixes = {}
def get_phone_prefixes_sorted_and_localized():
language = get_babel_locale() # changed from default implementation that used the django locale
cache_key = "phoneprefixes:all:{}".format(language)
if cache_key in _cached_phone_prefixes:
return _cached_phone_prefixes[cache_key]
val = cache.get(cache_key)
if val:
_cached_phone_prefixes[cache_key] = val
return val
val = []
locale = Locale(translation.to_locale(language))
for prefix, values in _COUNTRY_CODE_TO_REGION_CODE.items():
prefix = "+%d" % prefix
for country_code in values:
country_name = locale.territories.get(country_code)
if country_name:
val.append((prefix, "{} {}".format(country_name, prefix)))
val = sorted(val, key=lambda item: _collator.sort_key(item[1]))
_cached_phone_prefixes[cache_key] = val
cache.set(cache_key, val, 3600 * 24 * 30)
return val