Roll out agency content parity across locales

This commit is contained in:
2026-03-31 00:29:01 +02:00
parent 582efd017d
commit eef11801a6
4 changed files with 5041 additions and 141 deletions

View File

@@ -49,6 +49,7 @@ CTA_RULES = {
r"^Service",
r"^Dienstleistungen",
r"^Erstgespräch",
r"^Beratung",
r"^Einführ",
r"^Anpassung",
r"^Ansichts",
@@ -83,6 +84,7 @@ CTA_RULES = {
r"^Descubrir",
r"^Contactar",
r"^Planificar",
r"^Program",
r"^Programe",
r"^Concertar",
r"^Enviar",
@@ -141,6 +143,8 @@ def validate_cta(locale_code: str, field_path: str, normalized: str):
last_segment = field_path.split(".")[-1]
if last_segment not in CTA_FIELDS:
return []
if any(re.search(pattern, normalized) for pattern in CTA_RULES.get(locale_code, ())):
if any(
re.search(pattern, normalized) for pattern in CTA_RULES.get(locale_code, ())
):
return []
return [make_issue("cta_language_mismatch", field_path, normalized)]

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,18 @@ from django.db import transaction
from wagtail.blocks import StreamValue
from wagtail.models import Locale, Page
from mandelstudio.management.commands._agency_content import (
COMMON_CTA,
CTA_VARIANTS,
FOOTER_CONTENT,
NL_REPLACEMENTS,
)
from mandelstudio.management.commands._agency_content import (
body_for as localized_body_for,
)
from mandelstudio.management.commands._agency_content import (
footer_stream_data as localized_footer_stream_data,
)
from mandelstudio.models import LocalizedFooterContent
SOURCE_PAGE_IDS = {
@@ -129,129 +141,6 @@ PAGE_TITLE_MAP = {
},
}
COMMON_CTA = {
"nl": {
"primary": "Plan een kennismakingsgesprek",
"secondary": "Bekijk onze diensten",
},
"en": {"primary": "Book an introductory call", "secondary": "View our services"},
"de": {"primary": "Erstgespräch planen", "secondary": "Unsere Leistungen ansehen"},
"fr": {"primary": "Planifier un échange initial", "secondary": "Voir nos services"},
"es": {
"primary": "Planificar una reunión inicial",
"secondary": "Ver nuestros servicios",
},
"it": {
"primary": "Prenota un colloquio conoscitivo",
"secondary": "Scopri i nostri servizi",
},
"pt": {
"primary": "Agendar reunião introdutória",
"secondary": "Ver os nossos serviços",
},
"ru": {"primary": "Запланировать вводный звонок", "secondary": "Посмотреть услуги"},
}
CTA_VARIANTS = {
"nl": [
"Plan gratis gesprek",
"Plan intake",
"Plan dienstengesprek",
"Contact Support",
"Start jouw project",
"Vraag intake aan",
"Plan kennismaking",
"Bekijk diensten",
"Bekijk alle diensten",
"Vraag startergesprek aan",
"Plan startergesprek",
"Plan zakelijk gesprek",
"Start webshop traject",
"Vraag supportplan aan",
"Plan gratis kennismaking",
"Bekijk projectresultaten",
],
}
NL_REPLACEMENTS = {
"New": "Nieuw",
"Popular": "Populair",
"AI Search": "AI-zoekfunctie",
"custom blokken": "maatwerkblokken",
"monitoring-ready basis": "stabiele technische basis",
"Monitoring + fixes": "Monitoring en technische oplossingen",
"SEO-ready basis": "SEO-vriendelijke basis",
"Starter Website": "Starter-website",
"Business Website": "Zakelijke website",
"Support & Groei": "Onderhoud & groei",
"24u": "binnen 24 uur",
"24u Reactietijd": "Reactie binnen 24 uur",
"15m Intake call": "Intakegesprek van 15 minuten",
"100% Vrijblijvend": "Volledig vrijblijvend",
"Webshop Implementatie": "Webshop-implementatie",
"Doorlopend Verbetering": "Doorlopende verbetering",
"Monitoring-ready stack": "Stabiele technische basis",
}
FOOTER_CONTENT = {
"nl": {
"about": "<p>MandelBlog bouwt websites voor dienstverleners, studios en kleine teams die professioneel online willen staan zonder template-ruis.</p>",
"links_heading": "Snelle links",
"support_heading": "Plan een gesprek",
"support": '<p><a href="/contact/">Plan een kennismakingsgesprek</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/diensten/">Bekijk onze diensten</a></p>',
"mini": '<p><a href="/contact/">Contact</a> - <a href="/diensten/">Diensten</a> - <a href="/projecten/">Projecten</a> - MandelBlog Studio</p>',
},
"en": {
"about": "<p>MandelBlog builds websites for service businesses, studios and small teams that need a credible online presence without template clutter.</p>",
"links_heading": "Quick links",
"support_heading": "Book a call",
"support": '<p><a href="/en/contact/">Book an introductory call</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/en/services/">View our services</a></p>',
"mini": '<p><a href="/en/contact/">Contact</a> - <a href="/en/services/">Services</a> - <a href="/en/projects/">Projects</a> - MandelBlog Studio</p>',
},
"de": {
"about": "<p>MandelBlog entwickelt Websites für Dienstleister, Studios und kleine Teams, die professionell auftreten möchten, ohne Template-Ballast.</p>",
"links_heading": "Schnellzugriff",
"support_heading": "Gespräch planen",
"support": '<p><a href="/de/kontakt/">Erstgespräch planen</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/de/dienstleistungen/">Leistungen ansehen</a></p>',
"mini": '<p><a href="/de/kontakt/">Kontakt</a> - <a href="/de/dienstleistungen/">Dienstleistungen</a> - <a href="/de/projekte/">Projekte</a> - MandelBlog Studio</p>',
},
"fr": {
"about": "<p>MandelBlog conçoit des sites pour les sociétés de services, les studios et les petites équipes qui veulent une présence crédible, sans surcharge de template.</p>",
"links_heading": "Accès rapides",
"support_heading": "Planifier un échange",
"support": '<p><a href="/fr/contact/">Planifier un échange initial</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/fr/services/">Voir nos services</a></p>',
"mini": '<p><a href="/fr/contact/">Contact</a> - <a href="/fr/services/">Services</a> - <a href="/fr/projets/">Projets</a> - MandelBlog Studio</p>',
},
"es": {
"about": "<p>MandelBlog crea sitios web para empresas de servicios, estudios y pequeños equipos que quieren una presencia creíble sin aspecto de plantilla.</p>",
"links_heading": "Accesos rápidos",
"support_heading": "Planificar una reunión",
"support": '<p><a href="/es/contacto/">Planificar una reunión inicial</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/es/servicios/">Ver nuestros servicios</a></p>',
"mini": '<p><a href="/es/contacto/">Contacto</a> - <a href="/es/servicios/">Servicios</a> - <a href="/es/proyectos/">Proyectos</a> - MandelBlog Studio</p>',
},
"it": {
"about": "<p>MandelBlog realizza siti per aziende di servizi, studi e piccoli team che vogliono una presenza credibile senza leffetto template.</p>",
"links_heading": "Link rapidi",
"support_heading": "Prenota un colloquio",
"support": '<p><a href="/it/contatto/">Prenota un colloquio conoscitivo</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/it/servizi/">Scopri i nostri servizi</a></p>',
"mini": '<p><a href="/it/contatto/">Contatto</a> - <a href="/it/servizi/">Servizi</a> - <a href="/it/progetti/">Progetti</a> - MandelBlog Studio</p>',
},
"pt": {
"about": "<p>A MandelBlog cria sites para empresas de serviços, estúdios e pequenas equipas que precisam de uma presença credível sem aparência de template.</p>",
"links_heading": "Acessos rápidos",
"support_heading": "Agendar reunião",
"support": '<p><a href="/pt/contato/">Agendar reunião introdutória</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/pt/servicos/">Ver os nossos serviços</a></p>',
"mini": '<p><a href="/pt/contato/">Contacto</a> - <a href="/pt/servicos/">Serviços</a> - <a href="/pt/projetos/">Projetos</a> - MandelBlog Studio</p>',
},
"ru": {
"about": "<p>MandelBlog создаёт сайты для сервисных компаний, студий и небольших команд, которым нужен убедительный онлайн-образ без шаблонного шума.</p>",
"links_heading": "Быстрые ссылки",
"support_heading": "Назначить звонок",
"support": '<p><a href="/ru/kontakt/">Запланировать вводный звонок</a><br/><a href="mailto:info@mandelblog.com">info@mandelblog.com</a><br/><a href="/ru/uslugi/">Посмотреть услуги</a></p>',
"mini": '<p><a href="/ru/kontakt/">Контакт</a> - <a href="/ru/uslugi/">Услуги</a> - <a href="/ru/proekty/">Проекты</a> - MandelBlog Studio</p>',
},
}
def uid() -> str:
return str(uuid.uuid4())
@@ -1411,7 +1300,7 @@ class Command(BaseCommand):
if hasattr(page, "body"):
raw_data = list(page.body.raw_data)
if language_code == "nl" and key in {
if language_code in COMMON_CTA and key in {
"home",
"about",
"services",
@@ -1425,7 +1314,9 @@ class Command(BaseCommand):
}:
page.body = StreamValue(
page.body.stream_block,
nl_body_for(key, urls),
localized_body_for(
language_code, key, urls, PAGE_TITLE_MAP
),
is_lazy=True,
)
changed = True
@@ -1472,8 +1363,8 @@ class Command(BaseCommand):
"projects": urls.get("projects", "/"),
"contact": urls.get("contact", "/"),
}
footer_data, mini_data = footer_stream_data(
language_code, link_urls
footer_data, mini_data = localized_footer_stream_data(
language_code, link_urls, PAGE_TITLE_MAP
)
footer_obj.footer = StreamValue(
footer_obj.footer.stream_block, footer_data, is_lazy=True

View File

@@ -4,6 +4,8 @@ from django import template
from wagtail.models import Locale, Page
from mandelstudio.management.commands._agency_content import COMMON_CTA
register = template.Library()
SOURCE_PAGE_IDS = {
@@ -66,20 +68,8 @@ def agency_page(context, key: str):
return _translated_page(source_id, language_code)
CTA_LABELS = {
"nl": "Plan een kennismakingsgesprek",
"en": "Book an introductory call",
"de": "Erstgespräch planen",
"fr": "Planifier un échange initial",
"es": "Planificar una reunión inicial",
"it": "Prenota un colloquio conoscitivo",
"pt": "Agendar reunião introdutória",
"ru": "Запланировать вводный звонок",
}
@register.simple_tag(takes_context=True)
def agency_primary_cta(context):
request = context.get("request")
language_code = getattr(request, "LANGUAGE_CODE", None) or "nl"
return CTA_LABELS.get(language_code, CTA_LABELS["nl"])
return COMMON_CTA.get(language_code, COMMON_CTA["nl"])["primary"]