Перевод шаблонов URL-адресов
Django поддерживает переведенные строковые литералы в шаблонах URL-адресов. В одном шаблоне URL-адреса можно использовать перевод на каждый язык. Шаблоны URL-адресов можно помечать для перевода так же, как и строковые литералы, используя функцию gettext_lazy().
Отредактируйте файл urls.py приложения books, добавив переводные строковые литералы в шаблоны URL-адресов, как показано ниже:
from django.urls import path
from .views import book_list, create_book, update_book_details, book_detail, delete_book, update_book_status, \
book_list_sort
from django.utils.translation import gettext_lazy as _
urlpatterns = [
path("", book_list, name="book_list"),
path(_("create_book/"), create_book, name="create_book"),
path(_("update_book_details/<int:pk>/"), update_book_details, name="update_book_details"),
path(_("book_detail/<int:pk>/"), book_detail, name="book_detail"),
path(_("delete_book/<int:pk>/"), delete_book, name="delete_book"),
path(_("update_book_status/<int:pk>/"), update_book_status, name="update_book_status"),
path(_("book_list_sort/<filter>/<direction>/"), book_list_sort, name="book_list_sort"),
]
Затем отредактируем функцию сортировки book_list_sort() в файле views.py приложения books:
from django.utils.translation import gettext_lazy as _
# ...
@require_http_methods(['GET'])
def book_list_sort(request, filter, direction):
filter_dict = {_('id'): 'pk',
_('title'): 'title',
_('author'): 'author',
_('price'): 'price',
_('read'): 'read'}
if filter in filter_dict:
if direction == _('ascend'):
book_list = Book.objects.order_by(filter_dict[filter])
else:
book_list = Book.objects.order_by('-' + filter_dict[filter])
else:
book_list = Book.objects.all()
return render(request, 'partial_book_list.html', {'book_list': book_list})
И далее файл шаблонов base.html, добавим к переводу строковые литералы значений фильтра, направления сортировки, классов *-ascend и *-descend(это необходимо для корректной работы функции блокировки нажатой кнопки).
Примечание: обратите внимание, что теперь в htmx-атрибутах адресов запроса, в значениях filter и direction используются вместо строк - переменные с соответствующими именами, не забудьте удалить кавычки.
</head>
<body hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'>
<div class="container">
<div class="row mt-5">
<div class="col">
<!-- Форма для добавления новой книги -->
{% include "partial_create_book_form.html" %}
<!-- Таблица книг -->
<form class="form-inline">
<table class="table table-bordered table-sm mt-5">
{% trans "id" as id %}{% trans "title" as title %}
{% trans "author" as author %}{% trans "price" as price %}
{% trans "read" as read %}{% trans "ascend" as ascend %}
{% trans "descend" as descend %}
<thead>
<tr>
<!-- Заголовки столбцов таблицы -->
<!-- Заголовок номера книги -->
<th scope="col" style="width: 10%" class="text-center">
<small>
{% trans "No." %}
<a href=""
hx-get="{% url 'book_list_sort' filter=id direction=ascend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-down-square ms-1 {% trans 'id-ascend' %} disabled-button"></i>
</a>
<a href=""
hx-get="{% url 'book_list_sort' filter=id direction=descend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-up-square {% trans 'id-descend' %}"></i>
</a>
</small>
</th>
<!-- Заголовок названия книги -->
<th scope="col" style="width: 26%" class="text-center">
<small>
{% trans "Title" %}
<a href=""
hx-get="{% url 'book_list_sort' filter=title direction=ascend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-down-square ms-1 {% trans 'title-ascend' %}"></i>
</a>
<a href=""
hx-get="{% url 'book_list_sort' filter=title direction=descend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-up-square {% trans 'title-descend' %}"></i>
</a>
</small>
</th>
<!-- Заголовок автора книги -->
<th scope="col" style="width: 26%" class="text-center">
<small>
{% trans "Author" %}
<a href=""
hx-get="{% url 'book_list_sort' filter=author direction=ascend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-down-square ms-1 {% trans 'author-ascend' %}"></i>
</a>
<a href=""
hx-get="{% url 'book_list_sort' filter=author direction=descend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-up-square {% trans 'author-descend' %}"></i>
</a>
</small>
</th>
<!-- Заголовок цены книги -->
<th scope="col" style="width: 11%" class="text-center">
<small>
{% trans "Price ($)" %}
<a href=""
hx-get="{% url 'book_list_sort' filter=price direction=ascend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-down-square ms-1 {% trans 'price-ascend' %}"></i>
</a>
<a href=""
hx-get="{% url 'book_list_sort' filter=price direction=descend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-up-square {% trans 'price-descend' %}"></i>
</a>
</small>
</th>
<!-- Заголовок статуса книги -->
<th scope="col" style="width: 11%" class="text-center">
<small>
{% trans "Status" %}
<a href=""
hx-get="{% url 'book_list_sort' filter=read direction=descend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-down-square ms-1 {% trans 'read-descend' %}"></i>
</a>
<a href=""
hx-get="{% url 'book_list_sort' filter=read direction=ascend %}"
hx-target="#book-list"
hx-swap="innerHTML" >
<i class="table-icon bi bi-arrow-up-square {% trans 'read-ascend' %}"></i>
</a>
</small>
</th>
Там-же доработаем наш JavaScript-код, что-бы он корректно работал с переведёнными URL-адресами:
<script>
function cngElementsAtr(cls, atr, val){
var elems = document.getElementsByClassName(cls);
for(var i = 0; i < elems.length; i++) {
elems[i][atr] = val;
}
}
document.body.addEventListener('htmx:afterRequest', (event) => {
path_str = decodeURI(event.detail.pathInfo.requestPath);
if(path_str.includes("{% trans 'create_book' %}")){
cngElementsAtr('clrtxt', 'value', '');
}else if(path_str.includes("{% trans 'update_book_details' %}")){
if(event.detail.requestConfig.verb === 'put'){
cngElementsAtr('disbtn', 'disabled', true);
}else{
cngElementsAtr('disbtn', 'disabled', false);
}
}else if(path_str.includes("{% trans 'book_detail' %}")){
cngElementsAtr('disbtn', 'disabled', false);
}else if(path_str.includes("{% trans 'book_list_sort' %}")){
path_arr = path_str.split('/');
path_arr.pop()
curr_class = path_arr.pop()
curr_class = path_arr.pop() + '-' + curr_class
document.getElementsByClassName('disabled-button')[0].classList.remove('disabled-button');
document.getElementsByClassName(curr_class)[0].classList.add('disabled-button');
}
});
</script>