fix(i18n): translate pricing tiers, features, and content pages
Some checks failed
CI / ruff (push) Successful in 11s
CI / pytest (push) Failing after 49m22s
CI / validate (push) Successful in 26s
CI / dependency-scanning (push) Successful in 28s
CI / docs (push) Has been skipped
CI / deploy (push) Has been skipped

Add name_translations JSON column to SubscriptionTier for multi-language
tier names. Pre-resolve tier names and build dynamic feature lists from
module providers in route handlers. Fix Jinja2 macro scoping by importing
pricing partial with context. Backfill content_translations for all 43
content pages across 4 platforms (en/fr/de/lb).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 07:48:15 +01:00
parent 8b147f53c6
commit 3c7e4458af
9 changed files with 1544 additions and 33 deletions

View File

@@ -28,9 +28,12 @@ ROUTE_CONFIG = {
}
def _get_tiers_data(db: Session, platform_id: int | None = None) -> list[dict]:
def _get_tiers_data(
db: Session, platform_id: int | None = None, lang: str = "fr",
) -> list[dict]:
"""Build tier data for display in templates from database."""
from app.modules.billing.models import SubscriptionTier, TierCode
from app.modules.billing.services.feature_aggregator import feature_aggregator
filters = [
SubscriptionTier.is_active.is_(True),
@@ -49,12 +52,26 @@ def _get_tiers_data(db: Session, platform_id: int | None = None) -> list[dict]:
tiers = []
for tier in tiers_db:
feature_codes = sorted(tier.get_feature_codes())
# Build features list from declarations for template rendering
features = []
for code in feature_codes:
decl = feature_aggregator.get_declaration(code)
if decl:
features.append({
"code": code,
"name_key": decl.name_key,
"limit": tier.get_limit_for_feature(code),
"is_quantitative": decl.feature_type.value == "quantitative",
})
tiers.append({
"code": tier.code,
"name": tier.name,
"name": tier.get_translated_name(lang),
"price_monthly": tier.price_monthly_cents / 100,
"price_annual": (tier.price_annual_cents / 100) if tier.price_annual_cents else None,
"feature_codes": feature_codes,
"features": features,
"products_limit": tier.get_limit_for_feature("products_limit"),
"orders_per_month": tier.get_limit_for_feature("orders_per_month"),
"team_members": tier.get_limit_for_feature("team_members"),
@@ -156,11 +173,13 @@ async def homepage(
db, platform_id=platform_id, slug="home", include_unpublished=False
)
language = getattr(request.state, "language", "fr") or "fr"
if cms_homepage:
# Use CMS-based homepage with template selection
context = get_platform_context(request, db)
context["page"] = cms_homepage
context["tiers"] = _get_tiers_data(db, platform_id=platform_id)
context["tiers"] = _get_tiers_data(db, platform_id=platform_id, lang=language)
template_name = cms_homepage.template or "default"
template_path = f"cms/platform/homepage-{template_name}.html"
@@ -171,7 +190,7 @@ async def homepage(
# Fallback: Default homepage template with placeholder content
logger.info("[HOMEPAGE] No CMS homepage found, using default template with placeholders")
context = get_platform_context(request, db)
context["tiers"] = _get_tiers_data(db, platform_id=platform_id)
context["tiers"] = _get_tiers_data(db, platform_id=platform_id, lang=language)
return templates.TemplateResponse(
"cms/platform/homepage-default.html",