i18n: инфраструктура + переключатель языков + перевод меню (ru/uk/en)

Мультиязычность: русский — базовый (msgid), украинский и английский — переводы.

- Настройки: LocaleMiddleware, LANGUAGES=[ru,uk,en], LOCALE_PATHS, i18n
  context_processor; urls: django.conf.urls.i18n (set_language)
- Шелл index.html: {% load i18n %}, все пункты навигации/меню/пользовательского
  меню/нижней навигации помечены {% trans %}; динамический <html lang>;
  переключатель языков в хедере (select -> set_language)
- Каталоги locale/uk и locale/en: переведены строки меню/шелла (34), собраны .mo
- .gitignore: разрешено трекать locale/**/*.mo (нужны на проде, CI нет)

Остальные страницы пока на украинском (хардкод) — переводятся дальше поэтапно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 11:46:40 +03:00
parent fcdd5cb662
commit 2bc9615ce5
8 changed files with 3521 additions and 41 deletions
+2
View File
@@ -54,6 +54,8 @@ coverage.xml
# Translations
*.mo
*.pot
# ...кроме наших каталогов переводов (нужны на проде, CI-компиляции нет)
!locale/**/*.mo
# Django stuff:
*.log
+9 -1
View File
@@ -80,6 +80,7 @@ INSTALLED_APPS = [
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware', # выбор языка (после Session, до Common)
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
@@ -98,6 +99,7 @@ TEMPLATES = [
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.template.context_processors.i18n',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
@@ -121,7 +123,13 @@ AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
LANGUAGE_CODE = 'ru'
LANGUAGE_CODE = 'ru' # базовый язык интерфейса (исходные строки msgid)
LANGUAGES = [
('ru', 'Русский'),
('uk', 'Українська'),
('en', 'English'),
]
LOCALE_PATHS = [BASE_DIR / 'locale']
TIME_ZONE = 'Europe/Kiev'
USE_I18N = True
USE_TZ = True
+1
View File
@@ -23,6 +23,7 @@ from core import views
urlpatterns = [
path('admin/', admin.site.urls),
path('i18n/', include('django.conf.urls.i18n')), # set_language для переключателя мов
path('api/attendance/', include('apps.visit_manager.api.urls')),
path('', include('apps.employees.urls')),
path('', include('apps.ad_connector.urls')),
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+54 -40
View File
@@ -1,7 +1,8 @@
{% load common_tags %}
{% load static %}
{% load i18n %}
<!DOCTYPE html>
<html lang="uk">
<html lang="{{ LANGUAGE_CODE }}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
@@ -206,8 +207,8 @@
<img src="{% static 'assets/img/logosm.svg' %}" alt="АКС" style="width:100%; height:100%; object-fit:contain;">
</div>
<div class="sidebar-logo-text">
<div style="color:var(--color-sidebar-accent-foreground); font-size:0.8125rem; font-weight:700; line-height:1.2; letter-spacing:0.01em;">Мережа аптек</div>
<div style="color:var(--color-sidebar-foreground); font-size:0.625rem; opacity:0.6;">Портал користувача</div>
<div style="color:var(--color-sidebar-accent-foreground); font-size:0.8125rem; font-weight:700; line-height:1.2; letter-spacing:0.01em;">{% trans "Сеть аптек" %}</div>
<div style="color:var(--color-sidebar-foreground); font-size:0.625rem; opacity:0.6;">{% trans "Портал пользователя" %}</div>
</div>
</div>
@@ -216,7 +217,7 @@
<!-- Головне меню -->
<div>
<div class="nav-section-label">Головне меню</div>
<div class="nav-section-label">{% trans "Главное меню" %}</div>
<div style="display:flex; flex-direction:column; gap:2px;">
<a href="/dashboard/" class="nav-item"
@@ -225,7 +226,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<span class="nav-label-text">Головна</span>
<span class="nav-label-text">{% trans "Главная" %}</span>
</a>
<a href="/news/" class="nav-item"
@@ -235,7 +236,7 @@
<path d="M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-2 2Zm0 0a2 2 0 0 1-2-2v-9c0-1.1.9-2 2-2h2"/>
<path d="M18 14h-8M15 18h-5M10 6h8v4h-8V6Z"/>
</svg>
<span class="nav-label-text">Новини</span>
<span class="nav-label-text">{% trans "Новости" %}</span>
</a>
<a href="/employees/" class="nav-item"
@@ -246,7 +247,7 @@
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<span class="nav-label-text">Співробітники</span>
<span class="nav-label-text">{% trans "Сотрудники" %}</span>
</a>
<a href="/tasks/" class="nav-item"
@@ -256,7 +257,7 @@
<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
<path d="m9 14 2 2 4-4"/>
</svg>
<span class="nav-label-text">Задачі</span>
<span class="nav-label-text">{% trans "Задачи" %}</span>
</a>
<a href="/documents/" class="nav-item"
@@ -266,7 +267,7 @@
<path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/>
<path d="M14 2v4a2 2 0 0 0 2 2h4M10 9H8M16 13H8M16 17H8"/>
</svg>
<span class="nav-label-text">Документи</span>
<span class="nav-label-text">{% trans "Документы" %}</span>
</a>
<a href="/email/" class="nav-item"
@@ -276,7 +277,7 @@
<rect width="20" height="16" x="2" y="4" rx="2"/>
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/>
</svg>
<span class="nav-label-text">Електронна пошта</span>
<span class="nav-label-text">{% trans "Электронная почта" %}</span>
</a>
<a href="/chat/" class="nav-item"
@@ -285,7 +286,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>
</svg>
<span class="nav-label-text">Чат</span>
<span class="nav-label-text">{% trans "Чат" %}</span>
</a>
<a href="/calendar/" class="nav-item"
@@ -294,7 +295,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect width="18" height="18" x="3" y="4" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/>
</svg>
<span class="nav-label-text">Календар</span>
<span class="nav-label-text">{% trans "Календарь" %}</span>
</a>
<a href="/databases/" class="nav-item"
@@ -303,7 +304,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5V19a9 3 0 0 0 18 0V5"/><path d="M3 12a9 3 0 0 0 18 0"/>
</svg>
<span class="nav-label-text">Бази даних</span>
<span class="nav-label-text">{% trans "Базы данных" %}</span>
</a>
<a href="/reports/" class="nav-item"
@@ -312,7 +313,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/>
</svg>
<span class="nav-label-text">Звіти</span>
<span class="nav-label-text">{% trans "Отчёты" %}</span>
</a>
<a href="/purchases/" class="nav-item"
@@ -322,7 +323,7 @@
<circle cx="8" cy="21" r="1"/><circle cx="19" cy="21" r="1"/>
<path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/>
</svg>
<span class="nav-label-text">Закупівлі</span>
<span class="nav-label-text">{% trans "Закупки" %}</span>
</a>
<a href="/hr-portal/" class="nav-item"
@@ -331,7 +332,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect width="20" height="14" x="2" y="7" rx="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
</svg>
<span class="nav-label-text">HR портал</span>
<span class="nav-label-text">{% trans "HR портал" %}</span>
</a>
<a href="/settings/" class="nav-item"
@@ -341,7 +342,7 @@
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/>
<circle cx="12" cy="12" r="3"/>
</svg>
<span class="nav-label-text">Налаштування</span>
<span class="nav-label-text">{% trans "Настройки" %}</span>
</a>
</div>
@@ -349,7 +350,7 @@
<!-- Управління -->
<div>
<div class="nav-section-label">Управління</div>
<div class="nav-section-label">{% trans "Управление" %}</div>
<div style="display:flex; flex-direction:column; gap:2px;">
<a href="/dislocation/" class="nav-item"
@@ -358,7 +359,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/>
</svg>
<span class="nav-label-text">Дислокація</span>
<span class="nav-label-text">{% trans "Дислокация" %}</span>
</a>
<a href="/structure/" class="nav-item"
@@ -367,7 +368,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M2 4h12M2 8h8M2 12h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
</svg>
<span class="nav-label-text">Структура</span>
<span class="nav-label-text">{% trans "Структура" %}</span>
</a>
<a href="/pharmacies/" class="nav-item"
@@ -377,7 +378,7 @@
<path d="M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z"/>
<path d="M15 5.764v15"/><path d="M9 3.236v15"/>
</svg>
<span class="nav-label-text">Аптеки</span>
<span class="nav-label-text">{% trans "Аптеки" %}</span>
</a>
<a href="/utilities/" class="nav-item"
@@ -386,7 +387,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/>
</svg>
<span class="nav-label-text">Комунальні послуги</span>
<span class="nav-label-text">{% trans "Коммунальные услуги" %}</span>
</a>
<a href="/recruiting/" class="nav-item"
@@ -397,7 +398,7 @@
<circle cx="9" cy="7" r="4"/>
<line x1="19" x2="19" y1="8" y2="14"/><line x1="22" x2="16" y1="11" y2="11"/>
</svg>
<span class="nav-label-text">Рекрутинг</span>
<span class="nav-label-text">{% trans "Рекрутинг" %}</span>
</a>
<a href="/timetrack/" class="nav-item"
@@ -406,7 +407,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>
</svg>
<span class="nav-label-text">Облік робочого часу</span>
<span class="nav-label-text">{% trans "Учёт рабочего времени" %}</span>
</a>
</div>
@@ -414,7 +415,7 @@
<!-- Підтримка -->
<div>
<div class="nav-section-label">Підтримка</div>
<div class="nav-section-label">{% trans "Поддержка" %}</div>
<div style="display:flex; flex-direction:column; gap:2px;">
<a href="/help/" class="nav-item"
@@ -424,7 +425,7 @@
<circle cx="12" cy="12" r="10"/>
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>
</svg>
<span class="nav-label-text">Довідка</span>
<span class="nav-label-text">{% trans "Справка" %}</span>
</a>
<a href="/it-support/" class="nav-item"
@@ -434,7 +435,7 @@
<path d="M3 18v-6a9 9 0 0 1 18 0v6"/>
<path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"/>
</svg>
<span class="nav-label-text">Підтримка IT</span>
<span class="nav-label-text">{% trans "Поддержка IT" %}</span>
</a>
{% if request.user|is_it_staff %}
@@ -444,7 +445,7 @@
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect width="20" height="14" x="2" y="3" rx="2"/><line x1="8" x2="16" y1="21" y2="21"/><line x1="12" x2="12" y1="17" y2="21"/>
</svg>
<span class="nav-label-text">IT-відділ</span>
<span class="nav-label-text">{% trans "IT-отдел" %}</span>
</a>
{% endif %}
@@ -456,7 +457,7 @@
<rect width="8" height="8" x="2" y="2" rx="2"/><rect width="8" height="8" x="14" y="14" rx="2"/>
<path d="M10 6h4a2 2 0 0 1 2 2v2M14 18h-4a2 2 0 0 1-2-2v-2"/>
</svg>
<span class="nav-label-text">Active Directory</span>
<span class="nav-label-text">{% trans "Active Directory" %}</span>
</a>
{% endif %}
@@ -490,7 +491,7 @@
<circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/>
</svg>
<input type="text"
placeholder="Пошук..."
placeholder="{% trans 'Поиск...' %}"
class="input"
style="border:none; background:transparent; padding:0; box-shadow:none;"
hx-get="/api/search"
@@ -502,6 +503,19 @@
<div style="display:flex; align-items:center; gap:0.5rem;">
<!-- Language switcher -->
{% get_current_language as CUR_LANG %}
<form action="{% url 'set_language' %}" method="post" style="margin:0;">
{% csrf_token %}
<input type="hidden" name="next" value="/">
<select name="language" onchange="this.form.submit()" title="{% trans 'Язык' %}"
class="input" style="height:2rem; padding:0 0.5rem; font-size:0.75rem; width:auto; cursor:pointer;">
{% for code, name in LANGUAGES %}
<option value="{{ code }}" {% if code == CUR_LANG %}selected{% endif %}>{{ name }}</option>
{% endfor %}
</select>
</form>
<!-- Theme switcher -->
<div style="position:relative;" id="theme-switcher-wrapper">
<button onclick="toggleThemeSwitcher()" class="btn btn-ghost btn-icon" title="Тема інтерфейсу">
@@ -590,20 +604,20 @@
<div style="padding:0.25rem 0;">
<a href="/profile/" hx-get="/profile/" hx-target="#main-content" hx-push-url="/profile/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
Профіль
{% trans "Профиль" %}
</a>
<a href="/settings/" hx-get="/settings/" hx-target="#main-content" hx-push-url="/settings/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
Налаштування
{% trans "Настройки" %}
</a>
<a href="/help/" hx-get="/help/" hx-target="#main-content" hx-push-url="/help/" hx-indicator="#loader" onclick="closeUserMenu()" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-foreground); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>
Допомога
{% trans "Помощь" %}
</a>
<div style="height:1px; background:var(--color-border); margin:0.25rem 0;"></div>
<a href="{% url 'logout' %}" style="display:flex; align-items:center; gap:0.625rem; padding:0.5rem 1rem; font-size:0.8125rem; color:var(--color-destructive); text-decoration:none; transition:background 0.15s;" onmouseover="this.style.background='var(--color-muted)'" onmouseout="this.style.background='transparent'">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
Вихід
{% trans "Выход" %}
</a>
</div>
</div>
@@ -616,7 +630,7 @@
{% if page_template %}
{% include page_template %}
{% else %}
<div id="page-loader" style="padding:2rem;color:var(--color-muted-foreground);font-size:0.875rem;">Завантаження...</div>
<div id="page-loader" style="padding:2rem;color:var(--color-muted-foreground);font-size:0.875rem;">{% trans "Загрузка..." %}</div>
{% endif %}
</main>
</div>
@@ -633,7 +647,7 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/>
</svg>
<span>Головна</span>
<span>{% trans "Главная" %}</span>
</a>
<a href="/tasks/" class="bottom-nav-item"
@@ -643,7 +657,7 @@
<rect width="8" height="4" x="8" y="2" rx="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/>
<path d="m9 14 2 2 4-4"/>
</svg>
<span>Задачі</span>
<span>{% trans "Задачи" %}</span>
</a>
<a href="/employees/" class="bottom-nav-item"
@@ -654,7 +668,7 @@
<circle cx="9" cy="7" r="4"/>
<path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
</svg>
<span>Люди</span>
<span>{% trans "Люди" %}</span>
</a>
<a href="/chat/" class="bottom-nav-item"
@@ -663,14 +677,14 @@
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/>
</svg>
<span>Чат</span>
<span>{% trans "Чат" %}</span>
</a>
<button class="bottom-nav-item" onclick="toggleSidebar()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/>
</svg>
<span>Меню</span>
<span>{% trans "Меню" %}</span>
</button>
</nav>