feat(i18n): complete post-launch i18n phases 5-8
Some checks failed
Some checks failed
- Phase 5: Translate homepage-modern.html (~90 new locale keys, all hardcoded strings replaced with _() calls for dashboard mock, features, pricing tiers, testimonial sections) - Phase 6: Translate homepage-minimal.html (17 new locale keys for fallback content, features, and CTA sections) - Phase 7: Add multi-language page.title/content support with title_translations and content_translations JSON columns, Alembic migration cms_002, translated title/content resolution in templates, and seed script updates with tt() helper - Phase 8: Complete lb.json audit — fill 6 missing keys (messages, confirmations), also backfill same keys in fr.json and de.json All 4 locale files now have 340 keys with full parity. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -118,6 +118,21 @@ class ContentPage(Base):
|
||||
comment="Structured homepage sections (hero, features, pricing, cta) with i18n",
|
||||
)
|
||||
|
||||
# Multi-language title and content (JSON dicts keyed by language code)
|
||||
# e.g. {"en": "About Us", "fr": "À propos", "de": "Über uns", "lb": "Iwwer eis"}
|
||||
title_translations = Column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
default=None,
|
||||
comment="Language-keyed title dict for multi-language support",
|
||||
)
|
||||
content_translations = Column(
|
||||
JSON,
|
||||
nullable=True,
|
||||
default=None,
|
||||
comment="Language-keyed content dict for multi-language support",
|
||||
)
|
||||
|
||||
# SEO
|
||||
meta_description = Column(String(300), nullable=True)
|
||||
meta_keywords = Column(String(300), nullable=True)
|
||||
@@ -195,6 +210,26 @@ class ContentPage(Base):
|
||||
return "store_default"
|
||||
return "store_override"
|
||||
|
||||
def get_translated_title(self, lang: str, default_lang: str = "fr") -> str:
|
||||
"""Get title in the given language, falling back to default_lang then self.title."""
|
||||
if self.title_translations:
|
||||
return (
|
||||
self.title_translations.get(lang)
|
||||
or self.title_translations.get(default_lang)
|
||||
or self.title
|
||||
)
|
||||
return self.title
|
||||
|
||||
def get_translated_content(self, lang: str, default_lang: str = "fr") -> str:
|
||||
"""Get content in the given language, falling back to default_lang then self.content."""
|
||||
if self.content_translations:
|
||||
return (
|
||||
self.content_translations.get(lang)
|
||||
or self.content_translations.get(default_lang)
|
||||
or self.content
|
||||
)
|
||||
return self.content
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert to dictionary for API responses."""
|
||||
return {
|
||||
@@ -206,7 +241,9 @@ class ContentPage(Base):
|
||||
"store_name": self.store.name if self.store else None,
|
||||
"slug": self.slug,
|
||||
"title": self.title,
|
||||
"title_translations": self.title_translations,
|
||||
"content": self.content,
|
||||
"content_translations": self.content_translations,
|
||||
"content_format": self.content_format,
|
||||
"template": self.template,
|
||||
"sections": self.sections,
|
||||
|
||||
Reference in New Issue
Block a user