Skip to content

Commit ed1af30

Browse files
rsebillecodingjoe
andauthoredMay 23, 2023
[Django 4.1+] Make i18n works for LANGUAGE_CODE with a country code (#206)
When using a `LANGUAGE_CODE` with a country code and a supported language (_ie_: `fr-FR`) the current implementation of `Select2Mixin.i18n_name` will return `None` which means default _select2_ language, so English. Co-authored-by: Johannes Maron <[email protected]>
1 parent f0e9555 commit ed1af30

File tree

3 files changed

+83
-5
lines changed

3 files changed

+83
-5
lines changed
 

‎CONTRIBUTING.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ To install the package and its dependencies for development
1313
including tests dependencies, please do:
1414

1515
python -m pip install -e .[test]
16-
16+
1717
You may ran the tests via::
1818

1919
python -m pytest

‎django_select2/forms.py

+11-4
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,11 @@
5454

5555
import django
5656
from django import forms
57-
from django.contrib.admin.widgets import SELECT2_TRANSLATIONS, AutocompleteMixin
57+
from django.contrib.admin.widgets import AutocompleteMixin
5858
from django.core import signing
5959
from django.db.models import Q
6060
from django.forms.models import ModelChoiceIterator
6161
from django.urls import reverse
62-
from django.utils.translation import get_language
6362

6463
from .cache import cache
6564
from .conf import settings
@@ -89,7 +88,15 @@ class Select2Mixin:
8988
@property
9089
def i18n_name(self):
9190
"""Name of the i18n file for the current language."""
92-
return SELECT2_TRANSLATIONS.get(get_language())
91+
if django.VERSION < (4, 1):
92+
from django.contrib.admin.widgets import SELECT2_TRANSLATIONS
93+
from django.utils.translation import get_language
94+
95+
return SELECT2_TRANSLATIONS.get(get_language())
96+
else:
97+
from django.contrib.admin.widgets import get_select2_language
98+
99+
return get_select2_language()
93100

94101
def build_attrs(self, base_attrs, extra_attrs=None):
95102
"""Add select2 data attributes."""
@@ -258,7 +265,7 @@ def __init__(self, attrs=None, choices=(), **kwargs):
258265
if dependent_fields is not None:
259266
self.dependent_fields = dict(dependent_fields)
260267
if not (self.data_view or self.data_url):
261-
raise ValueError('You must ether specify "data_view" or "data_url".')
268+
raise ValueError('You must either specify "data_view" or "data_url".')
262269
self.userGetValTextFuncName = kwargs.pop("userGetValTextFuncName", "null")
263270

264271
def get_url(self):

‎tests/test_forms.py

+71
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
from collections.abc import Iterable
44

5+
import django
56
import pytest
67
from django.db.models import QuerySet
78
from django.urls import reverse
@@ -822,3 +823,73 @@ def test_dependent_fields_clear_after_change_parent(
822823
)
823824
)
824825
assert city2_container.text == ""
826+
827+
828+
@pytest.fixture(
829+
name="widget",
830+
params=[
831+
(Select2Widget, {}),
832+
(HeavySelect2Widget, {"data_view": "heavy_data_1"}),
833+
(HeavySelect2MultipleWidget, {"data_view": "heavy_data_1"}),
834+
(ModelSelect2Widget, {}),
835+
(ModelSelect2TagWidget, {}),
836+
],
837+
ids=lambda p: p[0],
838+
)
839+
def widget_fixture(request):
840+
widget_class, widget_kwargs = request.param
841+
return widget_class(**widget_kwargs)
842+
843+
844+
@pytest.mark.skipif(django.VERSION < (4, 1), reason="Only for Django 4.1+")
845+
@pytest.mark.parametrize(
846+
"locale,expected",
847+
[
848+
("fr-FR", "fr"),
849+
# Some locales with a country code are natively supported by select2's i18n
850+
("pt-BR", "pt-BR"),
851+
("sr-Cyrl", "sr-Cyrl"),
852+
],
853+
ids=repr,
854+
)
855+
def test_i18n_name_property_with_country_code_in_locale(widget, locale, expected):
856+
"""Test we fall back to the language code if the locale contain an unsupported country code."""
857+
with translation.override(locale):
858+
assert widget.i18n_name == expected
859+
860+
861+
@pytest.mark.skipif(django.VERSION < (4, 1), reason="Only for Django 4.1+")
862+
def test_i18n_media_js_with_country_code_in_locale(widget):
863+
translation.activate("fr-FR")
864+
assert tuple(widget.media._js) == (
865+
"admin/js/vendor/select2/select2.full.min.js",
866+
"admin/js/vendor/select2/i18n/fr.js",
867+
"django_select2/django_select2.js",
868+
)
869+
870+
871+
@pytest.mark.skipif(django.VERSION >= (4, 1), reason="Only for Django 4.0 and previous")
872+
@pytest.mark.parametrize(
873+
"locale,expected",
874+
[
875+
("fr-FR", None),
876+
# Some locales with a country code are natively supported by select2's i18n
877+
("pt-BR", "pt-BR"),
878+
("sr-Cyrl", "sr-Cyrl"),
879+
],
880+
)
881+
def test_i18n_name_property_with_country_code_in_locale_for_older_django(
882+
widget, locale, expected
883+
):
884+
"""No fallback for locale with an unsupported country code."""
885+
with translation.override(locale):
886+
assert widget.i18n_name == expected
887+
888+
889+
@pytest.mark.skipif(django.VERSION >= (4, 1), reason="Only for Django 4.0 and previous")
890+
def test_i18n_media_js_with_country_code_in_locale_for_older_django(widget):
891+
translation.activate("fr-FR")
892+
assert tuple(widget.media._js) == (
893+
"admin/js/vendor/select2/select2.full.min.js",
894+
"django_select2/django_select2.js",
895+
)

0 commit comments

Comments
 (0)
Please sign in to comment.