feat(i18n): add browser-language localization with Jinja2 _() and locale middleware
Some checks failed
ci/woodpecker/pr/pipeline Pipeline failed

Add i18n support to the blog web UI with 4 languages (en/ru/fr/de),
80 translation keys, automatic Accept-Language detection, persistent
locale cookie, and a language switcher dropdown in the header.

- Infrastructure: TranslationService, translation dicts, convenience _()
- Presentation: locale middleware, /web/lang/{locale} switcher route
- Templates: all 9 templates use {{ _(key, current_locale) }}
- Tests: 26 tests across TranslationService, locale detection helpers
- Docs: TEST_MODEL.md and FEATURE_INFRASTRUCTURE.md updated with TC-UNIT-811-821
This commit is contained in:
2026-05-10 16:22:06 +03:00
parent 4e6505c598
commit d32ad29abc
18 changed files with 1077 additions and 100 deletions

View File

@@ -1,26 +1,26 @@
{% extends "base.html" %}
{% block title %}About - Blog{% endblock %}
{% block meta_description %}A modern blog built with FastAPI and DDD architecture.{% endblock %}
{% block title %}{{ _('about.title', current_locale) }} - {{ _('base.default_title', current_locale) }}{% endblock %}
{% block meta_description %}{{ _('about.description', current_locale) }}{% endblock %}
{% block content %}
<div class="page-header" data-testid="page-header-about">
<h1 class="page-title" data-testid="page-title-about">About</h1>
<h1 class="page-title" data-testid="page-title-about">{{ _('about.page_title', current_locale) }}</h1>
</div>
<div class="card" data-testid="about-card">
<div class="card-body" data-testid="about-card-body">
<p data-testid="about-description">
A modern blog built with FastAPI and Domain-Driven Design architecture.
{{ _('about.description', current_locale) }}
</p>
<div class="divider" data-testid="about-divider"></div>
<p data-testid="about-user">
{% if user %}
Signed in as <strong>{{ user.username }}</strong>.
{{ _('about.signed_in', current_locale).format(username=user.username) }}
{% else %}
You are browsing as a guest.
{{ _('about.browsing_guest', current_locale) }}
{% endif %}
</p>
</div>
@@ -30,7 +30,7 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 0.5rem;">
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Back to Home
{{ _('about.back_home', current_locale) }}
</a>
</div>
</div>