diff --git a/app/modules/billing/definition.py b/app/modules/billing/definition.py index afb3a205..9773cfc8 100644 --- a/app/modules/billing/definition.py +++ b/app/modules/billing/definition.py @@ -34,6 +34,9 @@ def _get_platform_context(request: Any, db: Any, platform: Any) -> dict[str, Any """ from app.core.config import settings from app.modules.billing.models import SubscriptionTier, TierCode + from app.modules.billing.services.feature_aggregator import feature_aggregator + + language = getattr(request.state, "language", "fr") or "fr" tiers_db = ( db.query(SubscriptionTier) @@ -48,14 +51,28 @@ def _get_platform_context(request: Any, db: Any, platform: Any) -> dict[str, Any 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(language), "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"), diff --git a/app/modules/billing/migrations/versions/billing_002_add_tier_name_translations.py b/app/modules/billing/migrations/versions/billing_002_add_tier_name_translations.py new file mode 100644 index 00000000..9968b0dd --- /dev/null +++ b/app/modules/billing/migrations/versions/billing_002_add_tier_name_translations.py @@ -0,0 +1,31 @@ +"""add name_translations to subscription_tiers + +Revision ID: billing_002 +Revises: hosting_001 +Create Date: 2026-03-03 +""" + +import sqlalchemy as sa + +from alembic import op + +revision = "billing_002" +down_revision = "hosting_001" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + op.add_column( + "subscription_tiers", + sa.Column( + "name_translations", + sa.JSON(), + nullable=True, + comment="Language-keyed name dict for multi-language support", + ), + ) + + +def downgrade() -> None: + op.drop_column("subscription_tiers", "name_translations") diff --git a/app/modules/billing/models/subscription.py b/app/modules/billing/models/subscription.py index 69be3bfb..1b798d79 100644 --- a/app/modules/billing/models/subscription.py +++ b/app/modules/billing/models/subscription.py @@ -100,6 +100,12 @@ class SubscriptionTier(Base, TimestampMixin): code = Column(String(30), nullable=False, index=True) name = Column(String(100), nullable=False) + name_translations = Column( + JSON, + nullable=True, + default=None, + comment="Language-keyed name dict for multi-language support", + ) description = Column(Text, nullable=True) # Pricing (in cents for precision) @@ -154,6 +160,16 @@ class SubscriptionTier(Base, TimestampMixin): """Check if this tier includes a specific feature.""" return feature_code in self.get_feature_codes() + def get_translated_name(self, lang: str, default_lang: str = "fr") -> str: + """Get name in the given language, falling back to default_lang then self.name.""" + if self.name_translations: + return ( + self.name_translations.get(lang) + or self.name_translations.get(default_lang) + or self.name + ) + return self.name + # ============================================================================ # AddOnProduct - Purchasable add-ons diff --git a/app/modules/billing/templates/billing/platform/pricing.html b/app/modules/billing/templates/billing/platform/pricing.html index 56f44a61..29ddeef5 100644 --- a/app/modules/billing/templates/billing/platform/pricing.html +++ b/app/modules/billing/templates/billing/platform/pricing.html @@ -66,32 +66,23 @@ + {# Features list (dynamic from module providers) #} + {% if tier.features %} + {% endif %} {% if tier.is_enterprise %} diff --git a/app/modules/cms/routes/pages/platform.py b/app/modules/cms/routes/pages/platform.py index 43a3d150..467354ad 100644 --- a/app/modules/cms/routes/pages/platform.py +++ b/app/modules/cms/routes/pages/platform.py @@ -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", diff --git a/app/modules/cms/templates/cms/platform/homepage-default.html b/app/modules/cms/templates/cms/platform/homepage-default.html index df5dc22d..2b73f305 100644 --- a/app/modules/cms/templates/cms/platform/homepage-default.html +++ b/app/modules/cms/templates/cms/platform/homepage-default.html @@ -6,7 +6,7 @@ {% from 'cms/platform/sections/_hero.html' import render_hero %} {% from 'cms/platform/sections/_products.html' import render_products %} {% from 'cms/platform/sections/_features.html' import render_features %} -{% from 'cms/platform/sections/_pricing.html' import render_pricing %} +{% from 'cms/platform/sections/_pricing.html' import render_pricing with context %} {% from 'cms/platform/sections/_cta.html' import render_cta %} {% block title %} diff --git a/app/modules/cms/templates/cms/platform/sections/_pricing.html b/app/modules/cms/templates/cms/platform/sections/_pricing.html index 97d0d410..5537e324 100644 --- a/app/modules/cms/templates/cms/platform/sections/_pricing.html +++ b/app/modules/cms/templates/cms/platform/sections/_pricing.html @@ -2,10 +2,12 @@ {# Pricing section partial with multi-language support #} {# Parameters: - - pricing: PricingSection object (or dict) + - pricing: PricingSection object (or dict) from CMS sections JSON - lang: Current language code - default_lang: Fallback language - tiers: List of subscription tiers from DB (passed via context) + + Requires: import with context (for _() locale function) #} {# Helper macro: resolve a TranslatableText field with fallback #} @@ -80,9 +82,6 @@

{{ tier.name }}

-

- {{ tier.description or '' }} -

{# Price #}
@@ -102,15 +101,23 @@
- {# Features list #} + {# Features list (dynamic from module providers) #} {% if tier.features %} diff --git a/scripts/seed/create_default_content_pages.py b/scripts/seed/create_default_content_pages.py index 1089dcc1..39764bdf 100755 --- a/scripts/seed/create_default_content_pages.py +++ b/scripts/seed/create_default_content_pages.py @@ -670,6 +670,68 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

Built in Luxembourg

We understand the unique needs of Luxembourg commerce — from multilingual support (FR/DE/EN) to EU VAT compliance.

""", + "content_translations": tt( + # English + """
+

About Wizard

+

Wizard is the digital toolkit for Luxembourg businesses. We provide integrated solutions for order management, customer loyalty, and online presence.

+

Our Mission

+

To empower Luxembourg businesses with modern, easy-to-use digital tools that help them grow and thrive in the digital age.

+

Our Solutions

+ +

Built in Luxembourg

+

We understand the unique needs of Luxembourg commerce — from multilingual support (FR/DE/EN) to EU VAT compliance.

+
""", + # French + """
+

À propos de Wizard

+

Wizard est la boîte à outils numérique pour les entreprises luxembourgeoises. Nous proposons des solutions intégrées pour la gestion des commandes, la fidélisation client et la présence en ligne.

+

Notre mission

+

Donner aux entreprises luxembourgeoises des outils numériques modernes et faciles à utiliser pour les aider à croître et prospérer à l'ère du numérique.

+

Nos solutions

+ +

Conçu au Luxembourg

+

Nous comprenons les besoins uniques du commerce luxembourgeois — du support multilingue (FR/DE/EN) à la conformité TVA européenne.

+
""", + # German + """
+

Über Wizard

+

Wizard ist das digitale Toolkit für luxemburgische Unternehmen. Wir bieten integrierte Lösungen für Bestellverwaltung, Kundenbindung und Online-Präsenz.

+

Unsere Mission

+

Luxemburgische Unternehmen mit modernen, benutzerfreundlichen digitalen Werkzeugen zu stärken, die ihnen helfen, im digitalen Zeitalter zu wachsen und zu gedeihen.

+

Unsere Lösungen

+ +

Made in Luxembourg

+

Wir verstehen die einzigartigen Bedürfnisse des luxemburgischen Handels — von mehrsprachiger Unterstützung (FR/DE/EN) bis zur EU-MwSt-Konformität.

+
""", + # Luxembourgish + """
+

Iwwer Wizard

+

Wizard ass den digitalen Toolkit fir lëtzebuerger Betriber. Mir bidden integréiert Léisunge fir Bestellverwaltung, Clientsfidélisatioun an Online-Präsenz.

+

Eis Missioun

+

Lëtzebuerger Betriber mat modernen, einfach ze benotzenden digitale Werkzeuger ze stäerken, fir hinnen ze hëllefen am digitalen Zäitalter ze wuessen.

+

Eis Léisungen

+ +

Gemaach zu Lëtzebuerg

+

Mir verstinn déi eenzegaarteg Besoinë vum lëtzebuerger Commerce — vu méisproocheger Ënnerstëtzung (FR/DE/EN) bis zur EU-MwSt-Konformitéit.

+
""", + ), "meta_description": "Wizard — the digital toolkit for Luxembourg businesses. Order management, loyalty programs, and more.", "show_in_footer": True, "show_in_header": True, @@ -699,6 +761,92 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

Office

Luxembourg

""", + "content_translations": tt( + # English + """
+

Contact Wizard

+

We'd love to hear from you. Get in touch with our team.

+

General Inquiries

+ +

Sales

+

Interested in our solutions for your business?

+ +

Support

+

Already a customer? Our support team is here to help.

+ +

Office

+

Luxembourg

+
""", + # French + """
+

Contacter Wizard

+

Nous serions ravis d'avoir de vos nouvelles. Contactez notre équipe.

+

Renseignements généraux

+ +

Ventes

+

Intéressé par nos solutions pour votre entreprise ?

+ +

Support

+

Déjà client ? Notre équipe de support est là pour vous aider.

+ +

Bureau

+

Luxembourg

+
""", + # German + """
+

Kontaktieren Sie Wizard

+

Wir freuen uns, von Ihnen zu hören. Nehmen Sie Kontakt mit unserem Team auf.

+

Allgemeine Anfragen

+ +

Vertrieb

+

Interessiert an unseren Lösungen für Ihr Unternehmen?

+ +

Support

+

Bereits Kunde? Unser Support-Team hilft Ihnen gerne weiter.

+ +

Büro

+

Luxemburg

+
""", + # Luxembourgish + """
+

Wizard kontaktéieren

+

Mir géife gäre vun Iech héieren. Kontaktéiert eist Team.

+

Allgemeng Ufroen

+ +

Verkaf

+

Interesséiert un eise Léisunge fir Äre Betrib?

+ +

Support

+

Schonn Client? Eist Support-Team ass do fir Iech ze hëllefen.

+ +

Büro

+

Lëtzebuerg

+
""", + ), "meta_description": "Contact the Wizard team for inquiries about our business solutions.", "show_in_footer": True, "show_in_header": True, @@ -726,6 +874,84 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

Is my data secure?

Yes. We use industry-standard encryption and follow GDPR regulations for data protection.

""", + "content_translations": tt( + # English + """
+

Frequently Asked Questions

+

General

+

What is Wizard?

+

Wizard is a suite of digital tools for Luxembourg businesses, including order management (OMS), customer loyalty programs, and website building.

+

Who is Wizard for?

+

Wizard is designed for Luxembourg businesses of all sizes — from individual Letzshop sellers to multi-store retailers.

+

Pricing & Billing

+

Is there a free trial?

+

Yes! All our solutions offer a free trial period. No credit card required to start.

+

Can I switch plans?

+

Yes, you can upgrade or downgrade your plan at any time.

+

Technical

+

What languages are supported?

+

Our platform supports French, German, and English — the three official languages of Luxembourg.

+

Is my data secure?

+

Yes. We use industry-standard encryption and follow GDPR regulations for data protection.

+
""", + # French + """
+

Questions fréquemment posées

+

Général

+

Qu'est-ce que Wizard ?

+

Wizard est une suite d'outils numériques pour les entreprises luxembourgeoises, comprenant la gestion des commandes (OMS), les programmes de fidélité client et la création de sites web.

+

À qui s'adresse Wizard ?

+

Wizard est conçu pour les entreprises luxembourgeoises de toutes tailles — des vendeurs Letzshop individuels aux détaillants multi-boutiques.

+

Tarifs et facturation

+

Y a-t-il un essai gratuit ?

+

Oui ! Toutes nos solutions offrent une période d'essai gratuite. Aucune carte de crédit requise pour commencer.

+

Puis-je changer de plan ?

+

Oui, vous pouvez passer à un plan supérieur ou inférieur à tout moment.

+

Technique

+

Quelles langues sont supportées ?

+

Notre plateforme supporte le français, l'allemand et l'anglais — les trois langues officielles du Luxembourg.

+

Mes données sont-elles sécurisées ?

+

Oui. Nous utilisons un chiffrement aux normes de l'industrie et respectons les réglementations RGPD pour la protection des données.

+
""", + # German + """
+

Häufig gestellte Fragen

+

Allgemein

+

Was ist Wizard?

+

Wizard ist eine Suite digitaler Werkzeuge für luxemburgische Unternehmen, einschließlich Bestellverwaltung (OMS), Kundenbindungsprogramme und Website-Erstellung.

+

Für wen ist Wizard gedacht?

+

Wizard ist für luxemburgische Unternehmen jeder Größe konzipiert — von einzelnen Letzshop-Verkäufern bis hin zu Multi-Store-Einzelhändlern.

+

Preise und Abrechnung

+

Gibt es eine kostenlose Testversion?

+

Ja! Alle unsere Lösungen bieten eine kostenlose Testphase. Keine Kreditkarte erforderlich.

+

Kann ich den Plan wechseln?

+

Ja, Sie können Ihren Plan jederzeit upgraden oder downgraden.

+

Technik

+

Welche Sprachen werden unterstützt?

+

Unsere Plattform unterstützt Französisch, Deutsch und Englisch — die drei offiziellen Sprachen Luxemburgs.

+

Sind meine Daten sicher?

+

Ja. Wir verwenden branchenübliche Verschlüsselung und befolgen die DSGVO-Vorschriften zum Datenschutz.

+
""", + # Luxembourgish + """
+

Heefeg gestallte Froen

+

Allgemeng

+

Wat ass Wizard?

+

Wizard ass eng Suite vun digitale Werkzeuger fir lëtzebuerger Betriber, inklusiv Bestellverwaltung (OMS), Clientsfidélisatiounsprogrammer a Website-Erstellen.

+

Fir wie ass Wizard geduecht?

+

Wizard ass fir lëtzebuerger Betriber vun all Gréisst konzipéiert — vun eenzelne Letzshop-Verkeefer bis zu Multi-Store-Detaillisten.

+

Präisser a Rechnung

+

Gëtt et eng gratis Testversioun?

+

Jo! All eis Léisunge bidden eng gratis Testphas. Keng Kreditkaart néideg fir unzefänken.

+

Kann ech de Plang wiesselen?

+

Jo, Dir kënnt Äre Plang jidderzäit upgraden oder downgraden.

+

Technik

+

Wéi eng Sproochen ginn ënnerstëtzt?

+

Eis Plattform ënnerstëtzt Franséisch, Däitsch an Englesch — déi dräi offiziell Sproochen vu Lëtzebuerg.

+

Sinn meng Donnéeën sécher?

+

Jo. Mir benotzen Industriestandard-Verschlësselung a befollegen d'DSGVO-Virschrëften fir den Dateschutz.

+
""", + ), "meta_description": "Frequently asked questions about Wizard solutions for Luxembourg businesses.", "show_in_footer": True, "show_in_header": False, @@ -753,6 +979,68 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

Built for Luxembourg

From multilingual support to Luxembourg VAT compliance, OMS is designed for the local market.

""", + "content_translations": tt( + # English + """
+

About OMS by Wizard

+

OMS (omsflow.lu) is a lightweight order management system built specifically for Letzshop sellers in Luxembourg.

+

Why OMS?

+

Letzshop is a great marketplace, but it doesn't give sellers the back-office tools they need. OMS fills that gap with:

+ +

Built for Luxembourg

+

From multilingual support to Luxembourg VAT compliance, OMS is designed for the local market.

+
""", + # French + """
+

À propos d'OMS par Wizard

+

OMS (omsflow.lu) est un système de gestion de commandes léger conçu spécifiquement pour les vendeurs Letzshop au Luxembourg.

+

Pourquoi OMS ?

+

Letzshop est une excellente marketplace, mais elle ne fournit pas aux vendeurs les outils de back-office dont ils ont besoin. OMS comble ce manque avec :

+ +

Conçu pour le Luxembourg

+

Du support multilingue à la conformité TVA luxembourgeoise, OMS est conçu pour le marché local.

+
""", + # German + """
+

Über OMS von Wizard

+

OMS (omsflow.lu) ist ein leichtgewichtiges Bestellverwaltungssystem, das speziell für Letzshop-Verkäufer in Luxemburg entwickelt wurde.

+

Warum OMS?

+

Letzshop ist ein großartiger Marktplatz, bietet Verkäufern jedoch nicht die Back-Office-Tools, die sie benötigen. OMS schließt diese Lücke mit:

+ +

Für Luxemburg entwickelt

+

Von mehrsprachiger Unterstützung bis zur luxemburgischen MwSt-Konformität — OMS ist für den lokalen Markt konzipiert.

+
""", + # Luxembourgish + """
+

Iwwer OMS vun Wizard

+

OMS (omsflow.lu) ass e liichten Bestellverwaltungssystem, dat speziell fir Letzshop-Verkeefer zu Lëtzebuerg entwéckelt gouf.

+

Firwat OMS?

+

Letzshop ass e super Marché, awer et gëtt de Verkeefer net déi Back-Office-Tools déi si brauchen. OMS fëllt dës Lück mat:

+ +

Fir Lëtzebuerg entwéckelt

+

Vu méisproocheger Ënnerstëtzung bis zur lëtzebuerger MwSt-Konformitéit — OMS ass fir de lokale Marché konzipéiert.

+
""", + ), "meta_description": "OMS — lightweight order management for Letzshop sellers. Manage orders, inventory, and invoicing.", "show_in_footer": True, "show_in_header": True, @@ -775,6 +1063,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:
  • Email: sales@omsflow.lu
  • """, + "content_translations": tt( + # English + """
    +

    Contact OMS Support

    +

    Need help with your order management? We're here for you.

    +

    Support

    + +

    Sales

    +

    Interested in OMS for your Letzshop store?

    + +
    """, + # French + """
    +

    Contacter le support OMS

    +

    Besoin d'aide avec votre gestion de commandes ? Nous sommes là pour vous.

    +

    Support

    + +

    Ventes

    +

    Intéressé par OMS pour votre boutique Letzshop ?

    + +
    """, + # German + """
    +

    OMS Support kontaktieren

    +

    Brauchen Sie Hilfe bei Ihrer Bestellverwaltung? Wir sind für Sie da.

    +

    Support

    + +

    Vertrieb

    +

    Interessiert an OMS für Ihren Letzshop-Shop?

    + +
    """, + # Luxembourgish + """
    +

    OMS Support kontaktéieren

    +

    Braucht Dir Hëllef mat Ärer Bestellverwaltung? Mir sinn do fir Iech.

    +

    Support

    + +

    Verkaf

    +

    Interesséiert un OMS fir Äre Letzshop-Shop?

    + +
    """, + ), "meta_description": "Contact the OMS support team for help with order management.", "show_in_footer": True, "show_in_header": True, @@ -797,6 +1143,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Is there a free trial?

    Yes! Start with a free trial, no credit card required.

    """, + "content_translations": tt( + # English + """
    +

    Frequently Asked Questions

    +

    Do I need a Letzshop account?

    +

    While OMS works best with Letzshop integration, you can also use it as a standalone order management tool.

    +

    How does Letzshop sync work?

    +

    Enter your Letzshop API credentials and orders sync automatically. Setup takes about 2 minutes.

    +

    Is EU VAT invoicing included?

    +

    Yes, EU VAT invoicing is available on Professional and Enterprise plans. Luxembourg VAT is available on all plans.

    +

    Can I export my data?

    +

    Yes, you can export customers, orders, and invoices at any time.

    +

    Is there a free trial?

    +

    Yes! Start with a free trial, no credit card required.

    +
    """, + # French + """
    +

    Questions fréquemment posées

    +

    Ai-je besoin d'un compte Letzshop ?

    +

    Bien qu'OMS fonctionne mieux avec l'intégration Letzshop, vous pouvez aussi l'utiliser comme outil de gestion de commandes autonome.

    +

    Comment fonctionne la synchronisation Letzshop ?

    +

    Entrez vos identifiants API Letzshop et les commandes se synchronisent automatiquement. La configuration prend environ 2 minutes.

    +

    La facturation TVA UE est-elle incluse ?

    +

    Oui, la facturation TVA UE est disponible sur les plans Professionnel et Entreprise. La TVA luxembourgeoise est disponible sur tous les plans.

    +

    Puis-je exporter mes données ?

    +

    Oui, vous pouvez exporter les clients, commandes et factures à tout moment.

    +

    Y a-t-il un essai gratuit ?

    +

    Oui ! Commencez avec un essai gratuit, aucune carte de crédit requise.

    +
    """, + # German + """
    +

    Häufig gestellte Fragen

    +

    Brauche ich ein Letzshop-Konto?

    +

    OMS funktioniert am besten mit der Letzshop-Integration, kann aber auch als eigenständiges Bestellverwaltungstool verwendet werden.

    +

    Wie funktioniert die Letzshop-Synchronisation?

    +

    Geben Sie Ihre Letzshop-API-Zugangsdaten ein und die Bestellungen werden automatisch synchronisiert. Die Einrichtung dauert etwa 2 Minuten.

    +

    Ist die EU-MwSt-Rechnungsstellung enthalten?

    +

    Ja, die EU-MwSt-Rechnungsstellung ist in den Professional- und Enterprise-Plänen verfügbar. Luxemburger MwSt ist in allen Plänen verfügbar.

    +

    Kann ich meine Daten exportieren?

    +

    Ja, Sie können Kunden, Bestellungen und Rechnungen jederzeit exportieren.

    +

    Gibt es eine kostenlose Testversion?

    +

    Ja! Starten Sie mit einer kostenlosen Testversion, keine Kreditkarte erforderlich.

    +
    """, + # Luxembourgish + """
    +

    Heefeg gestallte Froen

    +

    Brauch ech e Letzshop-Konto?

    +

    OMS funktionéiert am beschten mat der Letzshop-Integratioun, kann awer och als eegenstännegt Bestellverwaltungs-Tool benotzt ginn.

    +

    Wéi funktionéiert d'Letzshop-Synchronisatioun?

    +

    Gitt Är Letzshop-API-Zougangsdaten an an d'Bestellunge synchroniséiere sech automatesch. D'Astellung dauert ongeféier 2 Minutten.

    +

    Ass d'EU-MwSt-Rechnungsstellung abegraff?

    +

    Jo, d'EU-MwSt-Rechnungsstellung ass an de Professional- a Enterprise-Pläng disponibel. Lëtzebuerger MwSt ass an alle Pläng disponibel.

    +

    Kann ech meng Donnéeën exportéieren?

    +

    Jo, Dir kënnt Clienten, Bestellungen a Rechnungen jidderzäit exportéieren.

    +

    Gëtt et eng gratis Testversioun?

    +

    Jo! Start mat enger gratis Testversioun, keng Kreditkaart néideg.

    +
    """, + ), "meta_description": "Frequently asked questions about OMS order management for Letzshop sellers.", "show_in_footer": True, "show_in_header": False, @@ -823,6 +1227,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Built for Luxembourg

    Multilingual support (FR/DE/EN) and local business features out of the box.

    """, + "content_translations": tt( + # English + """
    +

    About Loyalty by Wizard

    +

    Loyalty (rewardflow.lu) helps Luxembourg businesses create engaging customer loyalty programs.

    +

    What We Offer

    + +

    Built for Luxembourg

    +

    Multilingual support (FR/DE/EN) and local business features out of the box.

    +
    """, + # French + """
    +

    À propos de Loyalty par Wizard

    +

    Loyalty (rewardflow.lu) aide les entreprises luxembourgeoises à créer des programmes de fidélité client engageants.

    +

    Ce que nous offrons

    + +

    Conçu pour le Luxembourg

    +

    Support multilingue (FR/DE/EN) et fonctionnalités adaptées aux entreprises locales.

    +
    """, + # German + """
    +

    Über Loyalty von Wizard

    +

    Loyalty (rewardflow.lu) hilft luxemburgischen Unternehmen, ansprechende Kundenbindungsprogramme zu erstellen.

    +

    Was wir bieten

    + +

    Für Luxemburg entwickelt

    +

    Mehrsprachige Unterstützung (FR/DE/EN) und lokale Geschäftsfunktionen von Anfang an.

    +
    """, + # Luxembourgish + """
    +

    Iwwer Loyalty vun Wizard

    +

    Loyalty (rewardflow.lu) hëlleft lëtzebuerger Betriber, engagéierend Clientsfidélisatiounsprogrammer ze erstellen.

    +

    Wat mir bidden

    + +

    Fir Lëtzebuerg entwéckelt

    +

    Méisproocheg Ënnerstëtzung (FR/DE/EN) a lokal Geschäftsfunktiounen vun Ufank un.

    +
    """, + ), "meta_description": "Loyalty — customer loyalty programs for Luxembourg businesses. Points, rewards, and tiers.", "show_in_footer": True, "show_in_header": True, @@ -845,6 +1307,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:
  • Email: sales@rewardflow.lu
  • """, + "content_translations": tt( + # English + """
    +

    Contact Loyalty Support

    +

    Need help with your loyalty program? We're here for you.

    +

    Support

    + +

    Sales

    +

    Interested in a loyalty program for your business?

    + +
    """, + # French + """
    +

    Contacter le support Loyalty

    +

    Besoin d'aide avec votre programme de fidélité ? Nous sommes là pour vous.

    +

    Support

    + +

    Ventes

    +

    Intéressé par un programme de fidélité pour votre entreprise ?

    + +
    """, + # German + """
    +

    Loyalty Support kontaktieren

    +

    Brauchen Sie Hilfe mit Ihrem Treueprogramm? Wir sind für Sie da.

    +

    Support

    + +

    Vertrieb

    +

    Interessiert an einem Treueprogramm für Ihr Unternehmen?

    + +
    """, + # Luxembourgish + """
    +

    Loyalty Support kontaktéieren

    +

    Braucht Dir Hëllef mat Ärem Treiëprogramm? Mir sinn do fir Iech.

    +

    Support

    + +

    Verkaf

    +

    Interesséiert un engem Treiëprogramm fir Äre Betrib?

    + +
    """, + ), "meta_description": "Contact the Loyalty support team for help with your loyalty program.", "show_in_footer": True, "show_in_header": True, @@ -865,6 +1385,56 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Is there a free trial?

    Yes! Start with a free trial, no credit card required.

    """, + "content_translations": tt( + # English + """
    +

    Frequently Asked Questions

    +

    How do loyalty points work?

    +

    You define the rules — for example, 1 point per euro spent. Points can be redeemed for rewards from your catalog.

    +

    Can I customize the loyalty tiers?

    +

    Yes! You can create custom tiers with different names, thresholds, and benefits.

    +

    How do customers check their points?

    +

    Customers can check their balance through a personalized loyalty page or at your point of sale.

    +

    Is there a free trial?

    +

    Yes! Start with a free trial, no credit card required.

    +
    """, + # French + """
    +

    Questions fréquemment posées

    +

    Comment fonctionnent les points de fidélité ?

    +

    Vous définissez les règles — par exemple, 1 point par euro dépensé. Les points peuvent être échangés contre des récompenses de votre catalogue.

    +

    Puis-je personnaliser les niveaux de fidélité ?

    +

    Oui ! Vous pouvez créer des niveaux personnalisés avec des noms, seuils et avantages différents.

    +

    Comment les clients vérifient-ils leurs points ?

    +

    Les clients peuvent consulter leur solde via une page de fidélité personnalisée ou à votre point de vente.

    +

    Y a-t-il un essai gratuit ?

    +

    Oui ! Commencez avec un essai gratuit, aucune carte de crédit requise.

    +
    """, + # German + """
    +

    Häufig gestellte Fragen

    +

    Wie funktionieren Treuepunkte?

    +

    Sie definieren die Regeln — zum Beispiel 1 Punkt pro ausgegebenem Euro. Punkte können gegen Prämien aus Ihrem Katalog eingelöst werden.

    +

    Kann ich die Treuestufen anpassen?

    +

    Ja! Sie können benutzerdefinierte Stufen mit verschiedenen Namen, Schwellenwerten und Vorteilen erstellen.

    +

    Wie überprüfen Kunden ihre Punkte?

    +

    Kunden können ihren Kontostand über eine personalisierte Treueseite oder an Ihrer Verkaufsstelle überprüfen.

    +

    Gibt es eine kostenlose Testversion?

    +

    Ja! Starten Sie mit einer kostenlosen Testversion, keine Kreditkarte erforderlich.

    +
    """, + # Luxembourgish + """
    +

    Heefeg gestallte Froen

    +

    Wéi funktionéieren Treiëpunkten?

    +

    Dir definéiert d'Reegelen — zum Beispill 1 Punkt pro ausgeebenen Euro. Punkten kënnen géint Belounungen aus Ärem Katalog ageléist ginn.

    +

    Kann ech d'Treiëstufe personaliséieren?

    +

    Jo! Dir kënnt personaliséiert Stufe mat verschiddenen Nimm, Schwellenwäerter a Virdeeler erstellen.

    +

    Wéi kucken d'Clienten hir Punkten no?

    +

    Clientë kënnen hire Solde iwwer eng personaliséiert Treiësäit oder un Ärer Verkafsstell nokucken.

    +

    Gëtt et eng gratis Testversioun?

    +

    Jo! Start mat enger gratis Testversioun, keng Kreditkaart néideg.

    +
    """, + ), "meta_description": "Frequently asked questions about Loyalty customer loyalty programs.", "show_in_footer": True, "show_in_header": False, @@ -892,6 +1462,68 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Built for Luxembourg

    Multilingual support (FR/DE/EN/LB) and tailored for the Luxembourg business landscape.

    """, + "content_translations": tt( + # English + """
    +

    About HostWizard

    +

    HostWizard (hostwizard.lu) provides professional web hosting, domain registration, and website creation for Luxembourg businesses.

    +

    Our Services

    + +

    Built for Luxembourg

    +

    Multilingual support (FR/DE/EN/LB) and tailored for the Luxembourg business landscape.

    +
    """, + # French + """
    +

    À propos de HostWizard

    +

    HostWizard (hostwizard.lu) fournit l'hébergement web professionnel, l'enregistrement de domaines et la création de sites web pour les entreprises luxembourgeoises.

    +

    Nos services

    + +

    Conçu pour le Luxembourg

    +

    Support multilingue (FR/DE/EN/LB) et adapté au paysage commercial luxembourgeois.

    +
    """, + # German + """
    +

    Über HostWizard

    +

    HostWizard (hostwizard.lu) bietet professionelles Webhosting, Domainregistrierung und Website-Erstellung für luxemburgische Unternehmen.

    +

    Unsere Dienstleistungen

    + +

    Für Luxemburg entwickelt

    +

    Mehrsprachige Unterstützung (FR/DE/EN/LB) und maßgeschneidert für die luxemburgische Geschäftswelt.

    +
    """, + # Luxembourgish + """
    +

    Iwwer HostWizard

    +

    HostWizard (hostwizard.lu) bitt professionellt Webhosting, Domainregistréierung a Website-Erstellen fir lëtzebuerger Betriber.

    +

    Eis Servicer

    + +

    Fir Lëtzebuerg entwéckelt

    +

    Méisproocheg Ënnerstëtzung (FR/DE/EN/LB) an ugepasst un d'lëtzebuerger Geschäftswelt.

    +
    """, + ), "meta_description": "HostWizard — professional web hosting, domains, and website creation for Luxembourg businesses.", "show_in_footer": True, "show_in_header": True, @@ -914,6 +1546,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Website Maintenance

    Ongoing updates, security patches, and content changes. We keep your website running smoothly.

    """, + "content_translations": tt( + # English + """
    +

    HostWizard Services

    +

    Website Creation

    +

    We build professional websites for your business with our integrated CMS. You can edit your content anytime, or let us handle it for you.

    +

    Domain Names

    +

    Register and manage .lu domains and international domain names. We handle DNS configuration and renewals.

    +

    Professional Email

    +

    Get professional email addresses with your domain name (e.g., info@yourbusiness.lu). Multiple mailboxes available.

    +

    Hosting & SSL

    +

    Fast, secure hosting with free SSL certificates. Your website is always online and protected.

    +

    Website Maintenance

    +

    Ongoing updates, security patches, and content changes. We keep your website running smoothly.

    +
    """, + # French + """
    +

    Services HostWizard

    +

    Création de sites web

    +

    Nous créons des sites web professionnels pour votre entreprise avec notre CMS intégré. Vous pouvez modifier votre contenu à tout moment, ou nous laisser le gérer pour vous.

    +

    Noms de domaine

    +

    Enregistrez et gérez des domaines .lu et des noms de domaine internationaux. Nous gérons la configuration DNS et les renouvellements.

    +

    E-mail professionnel

    +

    Obtenez des adresses e-mail professionnelles avec votre nom de domaine (ex. : info@votreentreprise.lu). Plusieurs boîtes mail disponibles.

    +

    Hébergement et SSL

    +

    Hébergement rapide et sécurisé avec certificats SSL gratuits. Votre site web est toujours en ligne et protégé.

    +

    Maintenance de site web

    +

    Mises à jour continues, correctifs de sécurité et modifications de contenu. Nous maintenons votre site web en bon état de fonctionnement.

    +
    """, + # German + """
    +

    HostWizard Dienstleistungen

    +

    Website-Erstellung

    +

    Wir erstellen professionelle Websites für Ihr Unternehmen mit unserem integrierten CMS. Sie können Ihre Inhalte jederzeit bearbeiten oder uns damit beauftragen.

    +

    Domainnamen

    +

    Registrieren und verwalten Sie .lu-Domains und internationale Domainnamen. Wir kümmern uns um DNS-Konfiguration und Verlängerungen.

    +

    Professionelle E-Mail

    +

    Erhalten Sie professionelle E-Mail-Adressen mit Ihrem Domainnamen (z.B. info@ihrunternehmen.lu). Mehrere Postfächer verfügbar.

    +

    Hosting und SSL

    +

    Schnelles, sicheres Hosting mit kostenlosen SSL-Zertifikaten. Ihre Website ist immer online und geschützt.

    +

    Website-Wartung

    +

    Laufende Updates, Sicherheitspatches und Inhaltsänderungen. Wir halten Ihre Website reibungslos am Laufen.

    +
    """, + # Luxembourgish + """
    +

    HostWizard Servicer

    +

    Website-Erstellen

    +

    Mir bauen professionell Websäite fir Äre Betrib mat eisem integréierte CMS. Dir kënnt Ären Inhalt jidderzäit änneren, oder loosst eis dat fir Iech maachen.

    +

    Domänennimm

    +

    Registréiert a geréiert .lu-Domänen an international Domänennimm. Mir këmmeren eis ëm DNS-Konfiguratioun an Erneierungen.

    +

    Professionell E-Mail

    +

    Kritt professionell E-Mail-Adressen mat Ärem Domännumm (z.B. info@ärebetrib.lu). Méi Postfächer disponibel.

    +

    Hosting an SSL

    +

    Séiert, séchert Hosting mat gratis SSL-Zertifikater. Är Websäit ass ëmmer online a geschützt.

    +

    Website-Wartung

    +

    Lafend Updates, Sécherheetspatches an Inhaltsännerungen. Mir halen Är Websäit reibungslos am Lafen.

    +
    """, + ), "meta_description": "HostWizard services — website creation, domains, email, hosting, and maintenance for Luxembourg businesses.", "show_in_footer": True, "show_in_header": True, @@ -936,6 +1626,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    Monthly maintenance plans starting from €49/month.

    Contact us for a custom quote: info@hostwizard.lu

    """, + "content_translations": tt( + # English + """
    +

    HostWizard Pricing

    +

    Transparent pricing for all our services. No hidden fees.

    +

    Website Packages

    +

    Contact us for a personalized quote based on your needs. We start with a free POC (proof of concept) website so you can see the result before committing.

    +

    Domain Registration

    +

    .lu domains starting from €29/year. International domains available.

    +

    Email Hosting

    +

    Professional email from €5/mailbox/month.

    +

    Website Maintenance

    +

    Monthly maintenance plans starting from €49/month.

    +

    Contact us for a custom quote: info@hostwizard.lu

    +
    """, + # French + """
    +

    Tarifs HostWizard

    +

    Des tarifs transparents pour tous nos services. Aucun frais caché.

    +

    Forfaits sites web

    +

    Contactez-nous pour un devis personnalisé selon vos besoins. Nous commençons par un site POC (preuve de concept) gratuit pour que vous puissiez voir le résultat avant de vous engager.

    +

    Enregistrement de domaines

    +

    Domaines .lu à partir de 29 €/an. Domaines internationaux disponibles.

    +

    Hébergement e-mail

    +

    E-mail professionnel à partir de 5 €/boîte mail/mois.

    +

    Maintenance de site web

    +

    Plans de maintenance mensuels à partir de 49 €/mois.

    +

    Contactez-nous pour un devis personnalisé : info@hostwizard.lu

    +
    """, + # German + """
    +

    HostWizard Preise

    +

    Transparente Preise für alle unsere Dienstleistungen. Keine versteckten Gebühren.

    +

    Website-Pakete

    +

    Kontaktieren Sie uns für ein personalisiertes Angebot nach Ihren Bedürfnissen. Wir beginnen mit einer kostenlosen POC-Website (Proof of Concept), damit Sie das Ergebnis sehen können, bevor Sie sich verpflichten.

    +

    Domainregistrierung

    +

    .lu-Domains ab 29 €/Jahr. Internationale Domains verfügbar.

    +

    E-Mail-Hosting

    +

    Professionelle E-Mail ab 5 €/Postfach/Monat.

    +

    Website-Wartung

    +

    Monatliche Wartungspläne ab 49 €/Monat.

    +

    Kontaktieren Sie uns für ein individuelles Angebot: info@hostwizard.lu

    +
    """, + # Luxembourgish + """
    +

    HostWizard Präisser

    +

    Transparent Präisser fir all eis Servicer. Keng verstoppte Käschten.

    +

    Website-Paketen

    +

    Kontaktéiert eis fir en personaliséierten Devis no Äre Besoinë. Mir fänken mat enger gratis POC-Websäit (Proof of Concept) un, sou datt Dir d'Resultat gesitt ier Dir Iech engagéiert.

    +

    Domainregistréierung

    +

    .lu-Domänen ab 29 €/Joer. International Domänen disponibel.

    +

    E-Mail-Hosting

    +

    Professionell E-Mail ab 5 €/Postfach/Mount.

    +

    Website-Wartung

    +

    Monatslech Wartungspläng ab 49 €/Mount.

    +

    Kontaktéiert eis fir en individuellt Offert: info@hostwizard.lu

    +
    """, + ), "meta_description": "HostWizard pricing — transparent pricing for websites, domains, email, and hosting.", "show_in_footer": True, "show_in_header": True, @@ -963,6 +1711,84 @@ def _get_platform_pages(platform_code: str) -> list[dict]:
  • Email: support@hostwizard.lu
  • """, + "content_translations": tt( + # English + """
    +

    Contact HostWizard

    +

    Ready to bring your business online? Get in touch with our team.

    +

    General Inquiries

    + +

    Sales

    +

    Interested in a website for your business?

    + +

    Support

    +

    Already a customer? Our support team is here to help.

    + +
    """, + # French + """
    +

    Contacter HostWizard

    +

    Prêt à mettre votre entreprise en ligne ? Contactez notre équipe.

    +

    Renseignements généraux

    + +

    Ventes

    +

    Intéressé par un site web pour votre entreprise ?

    + +

    Support

    +

    Déjà client ? Notre équipe de support est là pour vous aider.

    + +
    """, + # German + """
    +

    HostWizard kontaktieren

    +

    Bereit, Ihr Unternehmen online zu bringen? Nehmen Sie Kontakt mit unserem Team auf.

    +

    Allgemeine Anfragen

    + +

    Vertrieb

    +

    Interessiert an einer Website für Ihr Unternehmen?

    + +

    Support

    +

    Bereits Kunde? Unser Support-Team hilft Ihnen gerne weiter.

    + +
    """, + # Luxembourgish + """
    +

    HostWizard kontaktéieren

    +

    Prett fir Äre Betrib online ze bréngen? Kontaktéiert eist Team.

    +

    Allgemeng Ufroen

    + +

    Verkaf

    +

    Interesséiert un enger Websäit fir Äre Betrib?

    + +

    Support

    +

    Schonn Client? Eist Support-Team ass do fir Iech ze hëllefen.

    + +
    """, + ), "meta_description": "Contact HostWizard for web hosting, domains, and website creation in Luxembourg.", "show_in_footer": True, "show_in_header": True, @@ -985,6 +1811,64 @@ def _get_platform_pages(platform_code: str) -> list[dict]:

    What is included in website maintenance?

    Security updates, content changes, performance monitoring, and technical support.

    """, + "content_translations": tt( + # English + """
    +

    Frequently Asked Questions

    +

    What is HostWizard?

    +

    HostWizard provides web hosting, domain registration, email hosting, and website creation services for Luxembourg businesses.

    +

    How does the POC website work?

    +

    We create a free proof-of-concept website for your business. If you like it, we can make it your live website on your own domain.

    +

    What domains can I register?

    +

    We support .lu domains and most international domain extensions (.com, .eu, .net, etc.).

    +

    Do you offer multilingual websites?

    +

    Yes! Our CMS supports French, German, English, and Luxembourgish out of the box.

    +

    What is included in website maintenance?

    +

    Security updates, content changes, performance monitoring, and technical support.

    +
    """, + # French + """
    +

    Questions fréquemment posées

    +

    Qu'est-ce que HostWizard ?

    +

    HostWizard fournit des services d'hébergement web, d'enregistrement de domaines, d'hébergement e-mail et de création de sites web pour les entreprises luxembourgeoises.

    +

    Comment fonctionne le site web POC ?

    +

    Nous créons un site web gratuit de preuve de concept pour votre entreprise. Si il vous plaît, nous pouvons en faire votre site web en production sur votre propre domaine.

    +

    Quels domaines puis-je enregistrer ?

    +

    Nous supportons les domaines .lu et la plupart des extensions de domaines internationaux (.com, .eu, .net, etc.).

    +

    Proposez-vous des sites web multilingues ?

    +

    Oui ! Notre CMS supporte le français, l'allemand, l'anglais et le luxembourgeois nativement.

    +

    Qu'est-ce qui est inclus dans la maintenance du site web ?

    +

    Mises à jour de sécurité, modifications de contenu, surveillance des performances et support technique.

    +
    """, + # German + """
    +

    Häufig gestellte Fragen

    +

    Was ist HostWizard?

    +

    HostWizard bietet Webhosting, Domainregistrierung, E-Mail-Hosting und Website-Erstellung für luxemburgische Unternehmen.

    +

    Wie funktioniert die POC-Website?

    +

    Wir erstellen eine kostenlose Proof-of-Concept-Website für Ihr Unternehmen. Wenn sie Ihnen gefällt, können wir sie zu Ihrer Live-Website auf Ihrer eigenen Domain machen.

    +

    Welche Domains kann ich registrieren?

    +

    Wir unterstützen .lu-Domains und die meisten internationalen Domain-Endungen (.com, .eu, .net usw.).

    +

    Bieten Sie mehrsprachige Websites an?

    +

    Ja! Unser CMS unterstützt Französisch, Deutsch, Englisch und Luxemburgisch von Haus aus.

    +

    Was ist in der Website-Wartung enthalten?

    +

    Sicherheitsupdates, Inhaltsänderungen, Leistungsüberwachung und technischer Support.

    +
    """, + # Luxembourgish + """
    +

    Heefeg gestallte Froen

    +

    Wat ass HostWizard?

    +

    HostWizard bitt Webhosting, Domainregistréierung, E-Mail-Hosting a Website-Erstellen fir lëtzebuerger Betriber.

    +

    Wéi funktionéiert d'POC-Websäit?

    +

    Mir erstellen eng gratis Proof-of-Concept-Websäit fir Äre Betrib. Wann se Iech gefält, kënne mir se zu Ärer Live-Websäit op Ärer eegener Domän maachen.

    +

    Wéi eng Domäne kann ech registréieren?

    +

    Mir ënnerstëtzen .lu-Domänen an déi meescht international Domain-Endungen (.com, .eu, .net asw.).

    +

    Bitt Dir méisproocheg Websäiten un?

    +

    Jo! Eise CMS ënnerstëtzt Franséisch, Däitsch, Englesch a Lëtzebuergesch vun Ufank un.

    +

    Wat ass an der Website-Wartung abegraff?

    +

    Sécherheetsupdaten, Inhaltsännerungen, Leeschtungsiwwerwaachung an technesche Support.

    +
    """, + ), "meta_description": "Frequently asked questions about HostWizard web hosting and website creation services.", "show_in_footer": True, "show_in_header": False, @@ -1018,6 +1902,80 @@ SHARED_PLATFORM_PAGES = [

    Contact

    For privacy-related questions, contact privacy@wizard.lu

    """, + "content_translations": tt( + # English + """
    +

    Privacy Policy

    +

    Last Updated: February 2026

    +

    Information We Collect

    +

    We collect information you provide directly:

    + +

    How We Use Your Information

    +

    We use your information to provide and improve our services, process payments, communicate with you, and comply with legal obligations.

    +

    Data Protection (GDPR)

    +

    We comply with the EU General Data Protection Regulation. You have the right to access, correct, delete, or export your personal data at any time.

    +

    Contact

    +

    For privacy-related questions, contact privacy@wizard.lu

    +
    """, + # French + """
    +

    Politique de confidentialité

    +

    Dernière mise à jour : février 2026

    +

    Informations que nous collectons

    +

    Nous collectons les informations que vous fournissez directement :

    + +

    Comment nous utilisons vos informations

    +

    Nous utilisons vos informations pour fournir et améliorer nos services, traiter les paiements, communiquer avec vous et respecter les obligations légales.

    +

    Protection des données (RGPD)

    +

    Nous sommes conformes au Règlement Général sur la Protection des Données de l'UE. Vous avez le droit d'accéder, corriger, supprimer ou exporter vos données personnelles à tout moment.

    +

    Contact

    +

    Pour toute question relative à la confidentialité, contactez privacy@wizard.lu

    +
    """, + # German + """
    +

    Datenschutzrichtlinie

    +

    Letzte Aktualisierung: Februar 2026

    +

    Informationen, die wir sammeln

    +

    Wir sammeln Informationen, die Sie direkt angeben:

    + +

    Wie wir Ihre Informationen verwenden

    +

    Wir verwenden Ihre Informationen, um unsere Dienste bereitzustellen und zu verbessern, Zahlungen zu verarbeiten, mit Ihnen zu kommunizieren und gesetzliche Verpflichtungen zu erfüllen.

    +

    Datenschutz (DSGVO)

    +

    Wir erfüllen die EU-Datenschutz-Grundverordnung. Sie haben jederzeit das Recht, auf Ihre persönlichen Daten zuzugreifen, sie zu korrigieren, zu löschen oder zu exportieren.

    +

    Kontakt

    +

    Für datenschutzbezogene Fragen kontaktieren Sie privacy@wizard.lu

    +
    """, + # Luxembourgish + """
    +

    Dateschutzrichtlinn

    +

    Lescht Aktualiséierung: Februar 2026

    +

    Informatiounen déi mir sammelen

    +

    Mir sammelen Informatiounen déi Dir direkt ugitt:

    + +

    Wéi mir Är Informatiounen benotzen

    +

    Mir benotzen Är Informatiounen fir eis Servicer ze bidden an ze verbesseren, Bezuelunge ze veraarbechten, mat Iech ze kommunizéieren an gesetzlech Obligatiounen z'erfëllen.

    +

    Dateschutz (DSGVO)

    +

    Mir erfëllen d'EU-Dateschutz-Grondveruerdnung. Dir hutt jidderzäit d'Recht, op Är perséinlech Donnéeën zouzegräifen, se ze korrigéieren, ze läschen oder z'exportéieren.

    +

    Kontakt

    +

    Fir Dateschutzfroen kontaktéiert privacy@wizard.lu

    +
    """, + ), "meta_description": "Privacy policy — how we collect, use, and protect your personal information.", "show_in_footer": False, "show_in_header": False, @@ -1046,6 +2004,84 @@ SHARED_PLATFORM_PAGES = [

    Contact

    For questions about these terms, contact legal@wizard.lu

    """, + "content_translations": tt( + # English + """
    +

    Terms of Service

    +

    Last Updated: February 2026

    +

    1. Acceptance of Terms

    +

    By accessing and using this platform, you accept and agree to be bound by these Terms of Service.

    +

    2. Services

    +

    We provide digital business tools including order management, loyalty programs, and website building services.

    +

    3. Account

    +

    You must provide accurate information and maintain the security of your account.

    +

    4. Payments

    +

    Subscription fees are billed monthly or annually. You may cancel at any time.

    +

    5. Data & Privacy

    +

    Your use of our services is also governed by our Privacy Policy.

    +

    6. Governing Law

    +

    These terms are governed by the laws of Luxembourg.

    +

    Contact

    +

    For questions about these terms, contact legal@wizard.lu

    +
    """, + # French + """
    +

    Conditions d'utilisation

    +

    Dernière mise à jour : février 2026

    +

    1. Acceptation des conditions

    +

    En accédant et en utilisant cette plateforme, vous acceptez d'être lié par ces Conditions d'utilisation.

    +

    2. Services

    +

    Nous fournissons des outils numériques pour les entreprises, notamment la gestion des commandes, les programmes de fidélité et les services de création de sites web.

    +

    3. Compte

    +

    Vous devez fournir des informations exactes et maintenir la sécurité de votre compte.

    +

    4. Paiements

    +

    Les frais d'abonnement sont facturés mensuellement ou annuellement. Vous pouvez annuler à tout moment.

    +

    5. Données et confidentialité

    +

    Votre utilisation de nos services est également régie par notre Politique de confidentialité.

    +

    6. Droit applicable

    +

    Ces conditions sont régies par les lois du Luxembourg.

    +

    Contact

    +

    Pour toute question sur ces conditions, contactez legal@wizard.lu

    +
    """, + # German + """
    +

    Nutzungsbedingungen

    +

    Letzte Aktualisierung: Februar 2026

    +

    1. Annahme der Bedingungen

    +

    Durch den Zugang und die Nutzung dieser Plattform akzeptieren Sie diese Nutzungsbedingungen und stimmen ihnen zu.

    +

    2. Dienstleistungen

    +

    Wir bieten digitale Geschäftstools, einschließlich Bestellverwaltung, Treueprogramme und Website-Erstellungsdienste.

    +

    3. Konto

    +

    Sie müssen genaue Informationen angeben und die Sicherheit Ihres Kontos gewährleisten.

    +

    4. Zahlungen

    +

    Abonnementgebühren werden monatlich oder jährlich berechnet. Sie können jederzeit kündigen.

    +

    5. Daten und Datenschutz

    +

    Ihre Nutzung unserer Dienste unterliegt auch unserer Datenschutzrichtlinie.

    +

    6. Anwendbares Recht

    +

    Diese Bedingungen unterliegen den Gesetzen Luxemburgs.

    +

    Kontakt

    +

    Für Fragen zu diesen Bedingungen kontaktieren Sie legal@wizard.lu

    +
    """, + # Luxembourgish + """
    +

    Notzungsbedingungen

    +

    Lescht Aktualiséierung: Februar 2026

    +

    1. Akzeptéierung vun de Bedingungen

    +

    Duerch den Zougang an d'Notzung vun dëser Plattform akzeptéiert Dir dës Notzungsbedingungen.

    +

    2. Servicer

    +

    Mir bidden digital Geschäftstools, inklusiv Bestellverwaltung, Treiëprogrammer a Website-Erstellungsservicer.

    +

    3. Konto

    +

    Dir musst korrekt Informatiounen uginn an d'Sécherheet vun Ärem Konto garantéieren.

    +

    4. Bezuelungen

    +

    Abonnementskäschte ginn monatslech oder jäerlech berechent. Dir kënnt jidderzäit kënnegen.

    +

    5. Donnéeën an Dateschutz

    +

    Är Notzung vun eise Servicer ënnerläit och eiser Dateschutzrichtlinn.

    +

    6. Applicabelt Recht

    +

    Dës Bedingunge sinn dem lëtzebuerger Recht ënnerworf.

    +

    Kontakt

    +

    Fir Froen zu dëse Bedingunge kontaktéiert legal@wizard.lu

    +
    """, + ), "meta_description": "Terms of service governing the use of our platform.", "show_in_footer": False, "show_in_header": False, @@ -1078,6 +2114,60 @@ STORE_DEFAULTS_COMMON = [
  • Phone: {{store_phone}}
  • """, + "content_translations": tt( + # English + """
    +

    About {{store_name}}

    +

    Welcome to {{store_name}}. We are committed to providing you with quality products and excellent service.

    +

    Our Story

    +

    {{store_name}} was founded with a simple mission: to deliver exceptional value to our customers.

    +

    Contact Us

    +

    Have questions? We'd love to hear from you.

    + +
    """, + # French + """
    +

    À propos de {{store_name}}

    +

    Bienvenue chez {{store_name}}. Nous nous engageons à vous fournir des produits de qualité et un service excellent.

    +

    Notre histoire

    +

    {{store_name}} a été fondé avec une mission simple : offrir une valeur exceptionnelle à nos clients.

    +

    Contactez-nous

    +

    Vous avez des questions ? Nous serions ravis d'avoir de vos nouvelles.

    + +
    """, + # German + """
    +

    Über {{store_name}}

    +

    Willkommen bei {{store_name}}. Wir sind bestrebt, Ihnen Qualitätsprodukte und exzellenten Service zu bieten.

    +

    Unsere Geschichte

    +

    {{store_name}} wurde mit einer einfachen Mission gegründet: unseren Kunden einen außergewöhnlichen Mehrwert zu bieten.

    +

    Kontaktieren Sie uns

    +

    Haben Sie Fragen? Wir freuen uns, von Ihnen zu hören.

    + +
    """, + # Luxembourgish + """
    +

    Iwwer {{store_name}}

    +

    Wëllkomm bei {{store_name}}. Mir setzen eis derfir an, Iech Qualitéitsprodukter an exzellente Service ze bidden.

    +

    Eis Geschicht

    +

    {{store_name}} gouf mat enger einfacher Missioun gegrënnt: eise Clienten en aussergewéinleche Méiwäert ze bidden.

    +

    Kontaktéiert eis

    +

    Hutt Dir Froen? Mir géife gäre vun Iech héieren.

    + +
    """, + ), "meta_description": "Learn about {{store_name}} — our story, values, and commitment to quality.", "show_in_footer": True, "show_in_header": True, @@ -1097,6 +2187,52 @@ STORE_DEFAULTS_COMMON = [

    We typically respond within 24 hours during business days.

    """, + "content_translations": tt( + # English + """
    +

    Contact {{store_name}}

    +

    We're here to help! Reach out to us.

    +

    Get in Touch

    + +

    We typically respond within 24 hours during business days.

    +
    """, + # French + """
    +

    Contacter {{store_name}}

    +

    Nous sommes là pour vous aider ! Contactez-nous.

    +

    Nous joindre

    + +

    Nous répondons généralement dans les 24 heures les jours ouvrables.

    +
    """, + # German + """
    +

    {{store_name}} kontaktieren

    +

    Wir sind hier, um zu helfen! Kontaktieren Sie uns.

    +

    Kontakt aufnehmen

    + +

    Wir antworten in der Regel innerhalb von 24 Stunden an Werktagen.

    +
    """, + # Luxembourgish + """
    +

    {{store_name}} kontaktéieren

    +

    Mir sinn do fir ze hëllefen! Kontaktéiert eis.

    +

    Kontakt ophuelen

    + +

    Mir äntweren normalerweis bannent 24 Stonnen un Aarbechtsdeeg.

    +
    """, + ), "meta_description": "Contact {{store_name}} for questions, support, or inquiries.", "show_in_footer": True, "show_in_header": True, @@ -1115,6 +2251,48 @@ STORE_DEFAULTS_COMMON = [

    Do you have a physical location?

    Please contact us for information about our location and visiting hours.

    """, + "content_translations": tt( + # English + """
    +

    Frequently Asked Questions

    +

    How can I contact you?

    +

    You can reach us at {{store_email}} or call {{store_phone}}.

    +

    What are your business hours?

    +

    We are available during regular business hours, Monday through Friday.

    +

    Do you have a physical location?

    +

    Please contact us for information about our location and visiting hours.

    +
    """, + # French + """
    +

    Questions fréquemment posées

    +

    Comment puis-je vous contacter ?

    +

    Vous pouvez nous joindre à {{store_email}} ou appeler le {{store_phone}}.

    +

    Quelles sont vos heures d'ouverture ?

    +

    Nous sommes disponibles pendant les heures d'ouverture habituelles, du lundi au vendredi.

    +

    Avez-vous un emplacement physique ?

    +

    Veuillez nous contacter pour des informations sur notre emplacement et nos heures de visite.

    +
    """, + # German + """
    +

    Häufig gestellte Fragen

    +

    Wie kann ich Sie kontaktieren?

    +

    Sie erreichen uns unter {{store_email}} oder telefonisch unter {{store_phone}}.

    +

    Was sind Ihre Geschäftszeiten?

    +

    Wir sind während der regulären Geschäftszeiten erreichbar, Montag bis Freitag.

    +

    Haben Sie einen physischen Standort?

    +

    Bitte kontaktieren Sie uns für Informationen über unseren Standort und Besuchszeiten.

    +
    """, + # Luxembourgish + """
    +

    Heefeg gestallte Froen

    +

    Wéi kann ech Iech kontaktéieren?

    +

    Dir erreecht eis ënner {{store_email}} oder rufft eis un ënner {{store_phone}}.

    +

    Wat sinn Är Geschäftszäiten?

    +

    Mir sinn während de reguläre Geschäftszäiten erreichbar, Méindes bis Freides.

    +

    Hutt Dir e physesche Standuert?

    +

    Kontaktéiert eis w.e.g. fir Informatiounen iwwer eise Standuert an eis Besuchszäiten.

    +
    """, + ), "meta_description": "Frequently asked questions about {{store_name}}.", "show_in_footer": True, "show_in_header": False, @@ -1132,6 +2310,44 @@ STORE_DEFAULTS_COMMON = [

    Your Rights

    Under GDPR, you have the right to access, correct, or delete your personal data. Contact us at {{store_email}}.

    """, + "content_translations": tt( + # English + """
    +

    Privacy Policy

    +

    {{store_name}} is committed to protecting your personal information.

    +

    Information We Collect

    +

    We collect information necessary to process your orders and provide customer service.

    +

    Your Rights

    +

    Under GDPR, you have the right to access, correct, or delete your personal data. Contact us at {{store_email}}.

    +
    """, + # French + """
    +

    Politique de confidentialité

    +

    {{store_name}} s'engage à protéger vos informations personnelles.

    +

    Informations que nous collectons

    +

    Nous collectons les informations nécessaires au traitement de vos commandes et à la fourniture du service client.

    +

    Vos droits

    +

    En vertu du RGPD, vous avez le droit d'accéder, de corriger ou de supprimer vos données personnelles. Contactez-nous à {{store_email}}.

    +
    """, + # German + """
    +

    Datenschutzrichtlinie

    +

    {{store_name}} verpflichtet sich zum Schutz Ihrer persönlichen Daten.

    +

    Informationen, die wir sammeln

    +

    Wir sammeln Informationen, die zur Bearbeitung Ihrer Bestellungen und zur Bereitstellung des Kundenservice erforderlich sind.

    +

    Ihre Rechte

    +

    Gemäß der DSGVO haben Sie das Recht, auf Ihre persönlichen Daten zuzugreifen, sie zu korrigieren oder zu löschen. Kontaktieren Sie uns unter {{store_email}}.

    +
    """, + # Luxembourgish + """
    +

    Dateschutzrichtlinn

    +

    {{store_name}} engagéiert sech fir de Schutz vun Äre perséinlechen Informatiounen.

    +

    Informatiounen déi mir sammelen

    +

    Mir sammelen Informatiounen déi néideg sinn fir Är Bestellungen ze veraarbechten an de Clientsservice ze bidden.

    +

    Är Rechter

    +

    Ënnert der DSGVO hutt Dir d'Recht, op Är perséinlech Donnéeën zouzegräifen, se ze korrigéieren oder ze läschen. Kontaktéiert eis ënner {{store_email}}.

    +
    """, + ), "meta_description": "Privacy policy for {{store_name}}.", "show_in_footer": False, "show_in_header": False, @@ -1150,6 +2366,44 @@ STORE_DEFAULTS_COMMON = [

    Contact

    For questions about these terms, contact us at {{store_email}}.

    """, + "content_translations": tt( + # English + """
    +

    Terms of Service

    +

    By using the services provided by {{store_name}}, you agree to these terms.

    +

    Orders

    +

    All orders are subject to availability and confirmation.

    +

    Contact

    +

    For questions about these terms, contact us at {{store_email}}.

    +
    """, + # French + """
    +

    Conditions d'utilisation

    +

    En utilisant les services fournis par {{store_name}}, vous acceptez ces conditions.

    +

    Commandes

    +

    Toutes les commandes sont soumises à la disponibilité et à la confirmation.

    +

    Contact

    +

    Pour toute question sur ces conditions, contactez-nous à {{store_email}}.

    +
    """, + # German + """
    +

    Nutzungsbedingungen

    +

    Durch die Nutzung der von {{store_name}} bereitgestellten Dienste stimmen Sie diesen Bedingungen zu.

    +

    Bestellungen

    +

    Alle Bestellungen unterliegen der Verfügbarkeit und Bestätigung.

    +

    Kontakt

    +

    Für Fragen zu diesen Bedingungen kontaktieren Sie uns unter {{store_email}}.

    +
    """, + # Luxembourgish + """
    +

    Notzungsbedingungen

    +

    Duerch d'Notzung vun de Servicer vu {{store_name}} stëmmt Dir dëse Bedingungen zou.

    +

    Bestellungen

    +

    All Bestellunge sinn un d'Disponibilitéit an d'Bestätegung gebonnen.

    +

    Kontakt

    +

    Fir Froen zu dëse Bedingunge kontaktéiert eis ënner {{store_email}}.

    +
    """, + ), "meta_description": "Terms of service for {{store_name}}.", "show_in_footer": False, "show_in_header": False, @@ -1179,6 +2433,72 @@ STORE_DEFAULTS_OMS_EXTRA = [

    Questions?

    Contact us at {{store_email}} for shipping inquiries.

    """, + "content_translations": tt( + # English + """
    +

    Shipping Policy

    +

    Shipping Methods

    +

    {{store_name}} offers multiple shipping options:

    + +

    Shipping Costs

    +

    Shipping costs are calculated based on weight and destination at checkout.

    +

    Tracking

    +

    You will receive a tracking number by email once your order ships.

    +

    Questions?

    +

    Contact us at {{store_email}} for shipping inquiries.

    +
    """, + # French + """
    +

    Politique de livraison

    +

    Méthodes de livraison

    +

    {{store_name}} propose plusieurs options de livraison :

    + +

    Frais de livraison

    +

    Les frais de livraison sont calculés en fonction du poids et de la destination lors du paiement.

    +

    Suivi

    +

    Vous recevrez un numéro de suivi par e-mail dès l'expédition de votre commande.

    +

    Des questions ?

    +

    Contactez-nous à {{store_email}} pour toute question relative à la livraison.

    +
    """, + # German + """
    +

    Versandrichtlinie

    +

    Versandmethoden

    +

    {{store_name}} bietet mehrere Versandoptionen an:

    + +

    Versandkosten

    +

    Die Versandkosten werden basierend auf Gewicht und Zielort bei der Kasse berechnet.

    +

    Sendungsverfolgung

    +

    Sie erhalten eine Sendungsverfolgungsnummer per E-Mail, sobald Ihre Bestellung versandt wird.

    +

    Fragen?

    +

    Kontaktieren Sie uns unter {{store_email}} für Versandanfragen.

    +
    """, + # Luxembourgish + """
    +

    Versandrichtlinn

    +

    Versandmethoden

    +

    {{store_name}} bitt verschidde Versandoptioune un:

    + +

    Versandkäschten

    +

    D'Versandkäschte ginn op Basis vum Gewiicht an der Destinatioun bei der Kees berechent.

    +

    Sendungsverfolgung

    +

    Dir kritt eng Sendungsverfolgungsnummer per E-Mail, soubal Är Bestellung verschéckt gëtt.

    +

    Froen?

    +

    Kontaktéiert eis ënner {{store_email}} fir Versandufroen.

    +
    """, + ), "meta_description": "Shipping policy for {{store_name}} — methods, costs, and delivery times.", "show_in_footer": True, "show_in_header": False, @@ -1203,6 +2523,72 @@ STORE_DEFAULTS_OMS_EXTRA = [

    Damaged Items

    If you receive a damaged item, contact us immediately at {{store_email}} with photos.

    """, + "content_translations": tt( + # English + """
    +

    Return & Refund Policy

    +

    Returns

    +

    {{store_name}} accepts returns within 14 days of delivery, in accordance with Luxembourg consumer protection law.

    +

    How to Return

    +
      +
    1. Contact us at {{store_email}} to initiate a return
    2. +
    3. Pack the item in its original condition
    4. +
    5. Ship using the provided return instructions
    6. +
    +

    Refunds

    +

    Refunds are processed within 14 days of receiving the returned item, back to the original payment method.

    +

    Damaged Items

    +

    If you receive a damaged item, contact us immediately at {{store_email}} with photos.

    +
    """, + # French + """
    +

    Politique de retour et remboursement

    +

    Retours

    +

    {{store_name}} accepte les retours dans les 14 jours suivant la livraison, conformément à la loi luxembourgeoise de protection du consommateur.

    +

    Comment retourner

    +
      +
    1. Contactez-nous à {{store_email}} pour initier un retour
    2. +
    3. Emballez l'article dans son état d'origine
    4. +
    5. Expédiez en suivant les instructions de retour fournies
    6. +
    +

    Remboursements

    +

    Les remboursements sont traités dans les 14 jours suivant la réception de l'article retourné, sur le moyen de paiement d'origine.

    +

    Articles endommagés

    +

    Si vous recevez un article endommagé, contactez-nous immédiatement à {{store_email}} avec des photos.

    +
    """, + # German + """
    +

    Rückgabe- und Erstattungsrichtlinie

    +

    Rückgaben

    +

    {{store_name}} akzeptiert Rückgaben innerhalb von 14 Tagen nach Lieferung, gemäß dem luxemburgischen Verbraucherschutzgesetz.

    +

    So geben Sie zurück

    +
      +
    1. Kontaktieren Sie uns unter {{store_email}}, um eine Rückgabe einzuleiten
    2. +
    3. Verpacken Sie den Artikel in seinem Originalzustand
    4. +
    5. Versenden Sie gemäß den bereitgestellten Rücksendeanweisungen
    6. +
    +

    Erstattungen

    +

    Erstattungen werden innerhalb von 14 Tagen nach Erhalt des zurückgesendeten Artikels auf die ursprüngliche Zahlungsmethode verarbeitet.

    +

    Beschädigte Artikel

    +

    Wenn Sie einen beschädigten Artikel erhalten, kontaktieren Sie uns sofort unter {{store_email}} mit Fotos.

    +
    """, + # Luxembourgish + """
    +

    Retour- a Rembourséierungsrichtlinn

    +

    Retouren

    +

    {{store_name}} akzeptéiert Retoure bannent 14 Deeg no der Liwwerung, am Aklang mat dem lëtzebuerger Konsumenteschutzgesetz.

    +

    Wéi retournéieren

    +
      +
    1. Kontaktéiert eis ënner {{store_email}} fir eng Retour unzefänken
    2. +
    3. Verpackt den Artikel a sengem originale Zoustand
    4. +
    5. Verschéckt no de geliwwerten Retourinstruktiounen
    6. +
    +

    Rembourséierungen

    +

    Rembourséierunge ginn bannent 14 Deeg no Erhalt vum retournéierten Artikel op déi ursprénglech Bezuelmethode veraarbecht.

    +

    Beschiedegt Artikelen

    +

    Wann Dir en beschiedegten Artikel kritt, kontaktéiert eis direkt ënner {{store_email}} mat Fotoen.

    +
    """, + ), "meta_description": "Return and refund policy for {{store_name}}.", "show_in_footer": True, "show_in_header": False, @@ -1242,6 +2628,27 @@ def _create_page( title = page_data["title"] if _page_exists(db, platform_id, slug, is_platform_page=is_platform_page): + # Backfill translations if they are currently NULL + existing = db.execute( + select(ContentPage).where( + ContentPage.platform_id == platform_id, + ContentPage.slug == slug, + ContentPage.is_platform_page == is_platform_page, + ContentPage.store_id.is_(None), + ) + ).scalar_one_or_none() + if existing: + updated = False + if existing.content_translations is None and page_data.get("content_translations"): + existing.content_translations = page_data["content_translations"] + updated = True + if existing.title_translations is None and page_data.get("title_translations"): + existing.title_translations = page_data["title_translations"] + updated = True + if updated: + existing.updated_at = datetime.now(UTC) + print(f" Backfilled translations: {title} (/{slug})") + return True # Count as created for reporting print(f" Skipped: {title} (/{slug}) - already exists") return False diff --git a/scripts/seed/init_production.py b/scripts/seed/init_production.py index b69267d1..e5236bd8 100644 --- a/scripts/seed/init_production.py +++ b/scripts/seed/init_production.py @@ -55,6 +55,7 @@ for _mod in [ "app.modules.orders.models", "app.modules.marketplace.models", "app.modules.cms.models", + "app.modules.prospecting.models", "app.modules.hosting.models", ]: with contextlib.suppress(ImportError): @@ -472,6 +473,10 @@ def create_subscription_tiers(db: Session, platform: Platform) -> int: { "code": "essential", "name": "Essential", + "name_translations": { + "en": "Essential", "fr": "Essentiel", + "de": "Basis", "lb": "Basis", + }, "price_monthly_cents": 2900, "price_annual_cents": 29000, "is_public": True, @@ -480,6 +485,10 @@ def create_subscription_tiers(db: Session, platform: Platform) -> int: { "code": "professional", "name": "Professional", + "name_translations": { + "en": "Professional", "fr": "Professionnel", + "de": "Professionell", "lb": "Professionell", + }, "price_monthly_cents": 7900, "price_annual_cents": 79000, "is_public": True, @@ -488,6 +497,10 @@ def create_subscription_tiers(db: Session, platform: Platform) -> int: { "code": "business", "name": "Business", + "name_translations": { + "en": "Business", "fr": "Business", + "de": "Business", "lb": "Business", + }, "price_monthly_cents": 14900, "price_annual_cents": 149000, "is_public": True, @@ -496,6 +509,10 @@ def create_subscription_tiers(db: Session, platform: Platform) -> int: { "code": "enterprise", "name": "Enterprise", + "name_translations": { + "en": "Enterprise", "fr": "Entreprise", + "de": "Enterprise", "lb": "Enterprise", + }, "price_monthly_cents": 29900, "price_annual_cents": None, "is_public": False, @@ -513,13 +530,19 @@ def create_subscription_tiers(db: Session, platform: Platform) -> int: ).scalar_one_or_none() if existing: - print_warning(f"Tier already exists: {existing.name} ({existing.code}) for {platform.name}") + # Backfill name_translations if missing + if existing.name_translations is None and tdef.get("name_translations"): + existing.name_translations = tdef["name_translations"] + print_success(f"Backfilled name_translations: {existing.name} ({existing.code}) for {platform.name}") + else: + print_warning(f"Tier already exists: {existing.name} ({existing.code}) for {platform.name}") continue tier = SubscriptionTier( platform_id=platform.id, code=tdef["code"], name=tdef["name"], + name_translations=tdef.get("name_translations"), price_monthly_cents=tdef["price_monthly_cents"], price_annual_cents=tdef["price_annual_cents"], is_public=tdef["is_public"],