Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 63 additions & 34 deletions bullet/countries/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
from re import Match, Pattern

from django.conf import settings
from django.http import HttpRequest, HttpResponseRedirect
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.utils import timezone, translation

from countries.logic import country
from countries.logic.cache import get_country_cache
from countries.models import BranchCountry

country_language_re: Pattern[str] = re.compile(r"^/([a-z]{2})/([^/]+)/")
url_path_re: Pattern[str] = re.compile(r"^/[a-z]{2}/[^/]+/(.*)")


def country_language_from_request(
Expand All @@ -27,47 +27,76 @@ class CountryLanguageMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def redirect_to_selector(self):
return HttpResponseRedirect(reverse("country_selector"))

def __call__(self, request: HttpRequest):
c, lang = country_language_from_request(request)

if c and not request._is_admin_domain:
cache: dict[int, dict[str, list[tuple[str, bool]]]] = get_country_cache()
if request.BRANCH is not None and (
c not in cache[request.BRANCH.id]
or (
(lang, True) not in cache[request.BRANCH.id][c]
and (lang, False) not in cache[request.BRANCH.id][c]
)
):
return HttpResponseRedirect(reverse("country_selector"))

country.activate(c)
request.COUNTRY_CODE = c

branch_country = BranchCountry.objects.get(
branch=request.BRANCH, country=c.upper()
)
timezone.activate(branch_country.timezone)

translation.activate(lang)
request.LANGUAGE_CODE = translation.get_language()
else:
if not c or request._is_admin_domain:
# Use default settings if not detected.
timezone.activate(settings.TIME_ZONE)
translation.activate(settings.LANGUAGE_CODE)
request.LANGUAGE_CODE = translation.get_language()
return self.get_response(request)

redirect = self.set_country_language(request, c, lang)
if redirect:
return redirect

response = self.get_response(request)
self.set_cookies(request, response)
return response

def get_url_part(self, request) -> str | None:
match = url_path_re.match(request.path_info)
if not match:
return None

return match.groups()[0]

if c and not request._is_admin_domain:
ckie = request.COOKIES.get("bullet_country", "")
expected = f"{c}|{lang}"
if ckie != expected:
response.set_cookie(
"bullet_country",
expected,
expires=365 * 24 * 60 * 60,
samesite="Lax",
def set_country_language(
self, request: HttpRequest, country_name, language
) -> HttpResponse | None:
branch_country: BranchCountry = BranchCountry.objects.filter(
branch=request.BRANCH, country=country_name.upper()
).first()

if branch_country is None:
return self.redirect_to_selector()

if language not in branch_country.languages:
url_part = self.get_url_part(request)
if branch_country.primary_language and url_part:
new_url = (
f"/{country_name}/{branch_country.primary_language}/{url_part}"
)
return HttpResponseRedirect(new_url)
return self.redirect_to_selector()

return response
timezone.activate(branch_country.timezone)

country.activate(country_name)
request.COUNTRY_CODE = country_name

translation.activate(language)
request.LANGUAGE_CODE = translation.get_language()

return None

def set_cookies(self, request, response):
country = request.COUNTRY_CODE
language = request.LANGUAGE_CODE

if not country or not language:
return

ckie = request.COOKIES.get("bullet_country", "")
expected = f"{country}|{language}"
if ckie != expected:
response.set_cookie(
"bullet_country",
expected,
expires=365 * 24 * 60 * 60,
samesite="Lax",
)
122 changes: 122 additions & 0 deletions bullet/countries/migrations/0008_branchcountry_primary_language.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Generated by Django 5.1 on 2024-10-28 08:36

import web.fields
from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("countries", "0007_branchcountry_hidden_languages_and_more"),
]

operations = [
migrations.AddField(
model_name="branchcountry",
name="primary_language",
field=web.fields.LanguageField(
blank=True,
choices=[
("af", "Afrikaans"),
("ar", "Arabic"),
("ar-dz", "Algerian Arabic"),
("ast", "Asturian"),
("az", "Azerbaijani"),
("bg", "Bulgarian"),
("be", "Belarusian"),
("bn", "Bengali"),
("br", "Breton"),
("bs", "Bosnian"),
("ca", "Catalan"),
("ckb", "Central Kurdish (Sorani)"),
("cs", "Czech"),
("cy", "Welsh"),
("da", "Danish"),
("de", "German"),
("dsb", "Lower Sorbian"),
("el", "Greek"),
("en", "English"),
("en-au", "Australian English"),
("en-gb", "British English"),
("eo", "Esperanto"),
("es", "Spanish"),
("es-ar", "Argentinian Spanish"),
("es-co", "Colombian Spanish"),
("es-mx", "Mexican Spanish"),
("es-ni", "Nicaraguan Spanish"),
("es-ve", "Venezuelan Spanish"),
("et", "Estonian"),
("eu", "Basque"),
("fa", "Persian"),
("fi", "Finnish"),
("fr", "French"),
("fy", "Frisian"),
("ga", "Irish"),
("gd", "Scottish Gaelic"),
("gl", "Galician"),
("he", "Hebrew"),
("hi", "Hindi"),
("hr", "Croatian"),
("hsb", "Upper Sorbian"),
("hu", "Hungarian"),
("hy", "Armenian"),
("ia", "Interlingua"),
("id", "Indonesian"),
("ig", "Igbo"),
("io", "Ido"),
("is", "Icelandic"),
("it", "Italian"),
("ja", "Japanese"),
("ka", "Georgian"),
("kab", "Kabyle"),
("kk", "Kazakh"),
("km", "Khmer"),
("kn", "Kannada"),
("ko", "Korean"),
("ky", "Kyrgyz"),
("lb", "Luxembourgish"),
("lt", "Lithuanian"),
("lv", "Latvian"),
("mk", "Macedonian"),
("ml", "Malayalam"),
("mn", "Mongolian"),
("mr", "Marathi"),
("ms", "Malay"),
("my", "Burmese"),
("nb", "Norwegian Bokmål"),
("ne", "Nepali"),
("nl", "Dutch"),
("nn", "Norwegian Nynorsk"),
("os", "Ossetic"),
("pa", "Punjabi"),
("pl", "Polish"),
("pt", "Portuguese"),
("pt-br", "Brazilian Portuguese"),
("ro", "Romanian"),
("ru", "Russian"),
("sk", "Slovak"),
("sl", "Slovenian"),
("sq", "Albanian"),
("sr", "Serbian"),
("sr-latn", "Serbian Latin"),
("sv", "Swedish"),
("sw", "Swahili"),
("ta", "Tamil"),
("te", "Telugu"),
("tg", "Tajik"),
("th", "Thai"),
("tk", "Turkmen"),
("tr", "Turkish"),
("tt", "Tatar"),
("udm", "Udmurt"),
("ug", "Uyghur"),
("uk", "Ukrainian"),
("ur", "Urdu"),
("uz", "Uzbek"),
("vi", "Vietnamese"),
("zh-hans", "Simplified Chinese"),
("zh-hant", "Traditional Chinese"),
],
max_length=8,
),
),
]
1 change: 1 addition & 0 deletions bullet/countries/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
class BranchCountry(models.Model):
branch = BranchField()
country = CountryField()
primary_language = LanguageField(blank=True)
languages = ChoiceArrayField(LanguageField())
timezone = TimeZoneField()
email = models.EmailField()
Expand Down