Files
boc/generate-pages.py
T

318 lines
16 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Generera alla quiXzoom landningssidor
15 marknader × 20 use cases = 300 sidor
"""
import os
import shutil
BASE_DIR = "/home/bernt/.openclaw/workspace/quixzoom-market-pages"
# Marknadskonfigurationer
MARKETS = {
"se": {"lang": "sv", "country": "Sverige", "country_en": "Sweden", "code": "SE",
"pay": "150500 kr", "tax": "Skatteverket", "curr": "kr",
"badge": "🇸🇪 Lanseras i Sverige · 1 augusti 2026", "domain": "quixzoom.se"},
"de": {"lang": "de", "country": "Deutschland", "country_en": "Germany", "code": "DE",
"pay": "1550 €", "tax": "Finanzamt", "curr": "",
"badge": "🇩🇪 Startet in Deutschland · August 2026", "domain": "quixzoom.de"},
"fr": {"lang": "fr", "country": "France", "country_en": "France", "code": "FR",
"pay": "1550 €", "tax": "DGFiP", "curr": "",
"badge": "🇫🇷 Lance en France · Août 2026", "domain": "quixzoom.fr"},
"nl": {"lang": "nl", "country": "Nederland", "country_en": "Netherlands", "code": "NL",
"pay": "1550 €", "tax": "Belastingdienst", "curr": "",
"badge": "🇳🇱 Lanceert in Nederland · Augustus 2026", "domain": "quixzoom.nl"},
"uk": {"lang": "en-gb", "country": "United Kingdom", "country_en": "United Kingdom", "code": "GB",
"pay": "£1242", "tax": "HMRC", "curr": "£",
"badge": "🇬🇧 Launching in the UK · August 2026", "domain": "quixzoom.co.uk"},
"it": {"lang": "it", "country": "Italia", "country_en": "Italy", "code": "IT",
"pay": "1550 €", "tax": "Agenzia delle Entrate", "curr": "",
"badge": "🇮🇹 Lancio in Italia · Agosto 2026", "domain": "quixzoom.it"},
"es": {"lang": "es", "country": "España", "country_en": "Spain", "code": "ES",
"pay": "1550 €", "tax": "Agencia Tributaria", "curr": "",
"badge": "🇪🇸 Lanzamiento en España · Agosto 2026", "domain": "quixzoom.es"},
"fi": {"lang": "fi", "country": "Suomi", "country_en": "Finland", "code": "FI",
"pay": "1550 €", "tax": "Verohallinto", "curr": "",
"badge": "🇫🇮 Lanserar i Finland · Elokuu 2026", "domain": "quixzoom.fi"},
"da": {"lang": "da", "country": "Danmark", "country_en": "Denmark", "code": "DK",
"pay": "100350 kr", "tax": "Skattestyrelsen", "curr": "kr",
"badge": "🇩🇰 Lancering i Danmark · August 2026", "domain": "quixzoom.dk"},
"at": {"lang": "de", "country": "Österreich", "country_en": "Austria", "code": "AT",
"pay": "1550 €", "tax": "BMF", "curr": "",
"badge": "🇦🇹 Start in Österreich · August 2026", "domain": "quixzoom.at"},
"be": {"lang": "nl", "country": "België", "country_en": "Belgium", "code": "BE",
"pay": "1550 €", "tax": "FOD Financiën", "curr": "",
"badge": "🇧🇪 Lancering in België · Augustus 2026", "domain": "quixzoom.be"},
"ch": {"lang": "de", "country": "Schweiz", "country_en": "Switzerland", "code": "CH",
"pay": "1550 CHF", "tax": "ESTV", "curr": "CHF",
"badge": "🇨🇭 Start in der Schweiz · August 2026", "domain": "quixzoom.ch"},
"no": {"lang": "no", "country": "Norge", "country_en": "Norway", "code": "NO",
"pay": "150500 kr", "tax": "Skatteetaten", "curr": "kr",
"badge": "🇳🇴 Lansering i Norge · August 2026", "domain": "quixzoom.no"},
"ie": {"lang": "en-ie", "country": "Ireland", "country_en": "Ireland", "code": "IE",
"pay": "€1550", "tax": "Revenue Commissioners", "curr": "",
"badge": "🇮🇪 Launching in Ireland · August 2026", "domain": "quixzoom.ie"},
"pl": {"lang": "pl", "country": "Polska", "country_en": "Poland", "code": "PL",
"pay": "60200 zł", "tax": "Ministerstwo Finansów", "curr": "",
"badge": "🇵🇱 Start w Polsce · Sierpień 2026", "domain": "quixzoom.pl"},
}
# Use cases med översättningar
USE_CASES = {
"bridge-inspection": {
"sv": "Broinspektion", "de": "Brückeninspektion", "fr": "Inspection de ponts",
"nl": "Bruginspectie", "en-gb": "Bridge Inspection", "it": "Ispezione ponti",
"es": "Inspección de puentes", "fi": "Sillan tarkastus", "da": "Broinspektion",
"no": "Broinspeksjon", "en-ie": "Bridge Inspection", "pl": "Inspekcja mostów"
},
"infrastructure-monitoring": {
"sv": "Infrastrukturövervakning", "de": "Infrastrukturüberwachung", "fr": "Surveillance d'infrastructure",
"nl": "Infrastructuurmonitoring", "en-gb": "Infrastructure Monitoring", "it": "Monitoraggio infrastrutture",
"es": "Monitoreo de infraestructura", "fi": "Infrastruktuurin valvonta", "da": "Infrastrukturovervågning",
"no": "Infrastrukturovervåking", "en-ie": "Infrastructure Monitoring", "pl": "Monitorowanie infrastruktury"
},
"property-documentation": {
"sv": "Fastighetsdokumentation", "de": "Immobiliendokumentation", "fr": "Documentation immobilière",
"nl": "Vastgoeddocumentatie", "en-gb": "Property Documentation", "it": "Documentazione immobiliare",
"es": "Documentación de propiedades", "fi": "Kiinteistödokumentaatio", "da": "Ejendomsdokumentation",
"no": "Eiendomsdokumentasjon", "en-ie": "Property Documentation", "pl": "Dokumentacja nieruchomości"
},
"storm-damage": {
"sv": "Stormskadebedömning", "de": "Sturmschadenbewertung", "fr": "Évaluation des dégâts de tempête",
"nl": "Stormschadebeoordeling", "en-gb": "Storm Damage Assessment", "it": "Valutazione danni da tempesta",
"es": "Evaluación de daños por tormenta", "fi": "Myrskyvaurioarvio", "da": "Stormskadevurdering",
"no": "Stormskadevurdering", "en-ie": "Storm Damage Assessment", "pl": "Ocena szkód po burzy"
},
"retail-audit": {
"sv": "Butiksaudit", "de": "Einzelhandelsaudit", "fr": "Audit de vente au détail",
"nl": "Retail audit", "en-gb": "Retail Audit", "it": "Audit retail",
"es": "Auditoría retail", "fi": "Vähittäiskaupan tarkastus", "da": "Detailhandelsaudit",
"no": "Detaljhandelsrevisjon", "en-ie": "Retail Audit", "pl": "Audyt detaliczny"
},
"ooh-audit": {
"sv": "OOH-audit", "de": "OOH-Audit", "fr": "Audit OOH",
"nl": "OOH-audit", "en-gb": "OOH Audit", "it": "Audit OOH",
"es": "Auditoría OOH", "fi": "OOH-tarkastus", "da": "OOH-audit",
"no": "OOH-revisjon", "en-ie": "OOH Audit", "pl": "Audyt OOH"
},
"construction-progress": {
"sv": "Byggframsteg", "de": "Baufortschritt", "fr": "Progrès de construction",
"nl": "Bouwvoortgang", "en-gb": "Construction Progress", "it": "Avanzamento lavori",
"es": "Progreso de construcción", "fi": "Rakennustyön edistyminen", "da": "Byggefremgang",
"no": "Byggefremskridt", "en-ie": "Construction Progress", "pl": "Postęp budowy"
},
"facade-inspection": {
"sv": "Fasadinspektion", "de": "Fassadeninspektion", "fr": "Inspection de façade",
"nl": "Gevelinspectie", "en-gb": "Facade Inspection", "it": "Ispezione facciata",
"es": "Inspección de fachadas", "fi": "Julkisivutarkastus", "da": "Facadeinspektion",
"no": "Fasadeinspeksjon", "en-ie": "Facade Inspection", "pl": "Inspekcja elewacji"
},
"roof-inspection": {
"sv": "Takinspektion", "de": "Dachinspektion", "fr": "Inspection de toit",
"nl": "Dakinspectie", "en-gb": "Roof Inspection", "it": "Ispezione tetto",
"es": "Inspección de tejados", "fi": "Kattotarkastus", "da": "Taginspektion",
"no": "Takinspeksjon", "en-ie": "Roof Inspection", "pl": "Inspekcja dachu"
},
"road-condition": {
"sv": "Vägcondition", "de": "Straßenzustand", "fr": "État des routes",
"nl": "Wegconditie", "en-gb": "Road Condition", "it": "Condizione stradale",
"es": "Condición de carreteras", "fi": "Tien kunto", "da": "Vejtilstand",
"no": "Veitilstand", "en-ie": "Road Condition", "pl": "Stan dróg"
},
"signage-audit": {
"sv": "Skyltaudit", "de": "Beschilderungsaudit", "fr": "Audit de signalisation",
"nl": "Signalisatie-audit", "en-gb": "Signage Audit", "it": "Audit segnaletica",
"es": "Auditoría de señalización", "fi": "Opastetarkastus", "da": "Skilteaudit",
"no": "Skiltingrevisjon", "en-ie": "Signage Audit", "pl": "Audyt oznakowania"
},
"parking-audit": {
"sv": "Parkeringsaudit", "de": "Parkplatz-Audit", "fr": "Audit de stationnement",
"nl": "Parkeer-audit", "en-gb": "Parking Audit", "it": "Audit parcheggi",
"es": "Auditoría de aparcamiento", "fi": "Pysäköintitarkastus", "da": "Parkeringsaudit",
"no": "Parkeringsrevisjon", "en-ie": "Parking Audit", "pl": "Audyt parkingów"
},
"asset-tracking": {
"sv": "Tillgångsspårning", "de": "Asset Tracking", "fr": "Suivi d'actifs",
"nl": "Asset tracking", "en-gb": "Asset Tracking", "it": "Tracciamento asset",
"es": "Seguimiento de activos", "fi": "Omaisuuden seuranta", "da": "Asset tracking",
"no": "Eiendomssporing", "en-ie": "Asset Tracking", "pl": "Śledzenie zasobów"
},
"environmental-survey": {
"sv": "Miljöinventering", "de": "Umwelterhebung", "fr": "Enquête environnementale",
"nl": "Milieudenquête", "en-gb": "Environmental Survey", "it": "Indagine ambientale",
"es": "Estudio medioambiental", "fi": "Ympäristöselvitys", "da": "Miljøundersøgelse",
"no": "Miljøundersøkelse", "en-ie": "Environmental Survey", "pl": "Badanie środowiskowe"
},
"insurance-claim": {
"sv": "Försäkringsärende", "de": "Versicherungsfall", "fr": "Réclamation d'assurance",
"nl": "Verzekeringsclaim", "en-gb": "Insurance Claim", "it": "Sinistro assicurativo",
"es": "Reclamación de seguro", "fi": "Vakuutusvaade", "da": "Forsikringskrav",
"no": "Forsikringskrav", "en-ie": "Insurance Claim", "pl": "Roszczenie ubezpieczeniowe"
},
"lease-audit": {
"sv": "Hyresaudit", "de": "Lease-Audit", "fr": "Audit de bail",
"nl": "Lease audit", "en-gb": "Lease Audit", "it": "Audit locazione",
"es": "Auditoría de arrendamiento", "fi": "Vuokraustarkastus", "da": "Leasingaudit",
"no": "Leasingrevisjon", "en-ie": "Lease Audit", "pl": "Audyt leasingowy"
},
"event-documentation": {
"sv": "Eventdokumentation", "de": "Eventdokumentation", "fr": "Documentation d'événement",
"nl": "Evenementdocumentatie", "en-gb": "Event Documentation", "it": "Documentazione eventi",
"es": "Documentación de eventos", "fi": "Tapahtumadokumentaatio", "da": "Begivenhedsdokumentation",
"no": "Arrangementsdokumentasjon", "en-ie": "Event Documentation", "pl": "Dokumentacja wydarzeń"
},
"pre-purchase-inspection": {
"sv": "Köpesbesiktning", "de": "Kaufinspektion", "fr": "Inspection pré-achat",
"nl": "Pre-aankoopinspectie", "en-gb": "Pre-Purchase Inspection", "it": "Ispezione pre-acquisto",
"es": "Inspección pre-compra", "fi": "Esihankintatarkastus", "da": "Forhåndskøbsinspektion",
"no": "Forhåndsinspeksjon", "en-ie": "Pre-Purchase Inspection", "pl": "Inspekcja przedzakupowa"
},
"rental-inspection": {
"sv": "Hyresinspektion", "de": "Mietinspektion", "fr": "Inspection locative",
"nl": "Huurinspectie", "en-gb": "Rental Inspection", "it": "Ispezione locazione",
"es": "Inspección de alquiler", "fi": "Vuokraustarkastus", "da": "Lejeinspektion",
"no": "Leieinspeksjon", "en-ie": "Rental Inspection", "pl": "Inspekcja wynajmu"
},
"accessibility-audit": {
"sv": "Tillgänglighetsaudit", "de": "Barrierefreiheits-Audit", "fr": "Audit d'accessibilité",
"nl": "Toegankelijkheidsaudit", "en-gb": "Accessibility Audit", "it": "Audit accessibilità",
"es": "Auditoría de accesibilidad", "fi": "Saavutettavuustarkastus", "da": "Tilgængelighedsaudit",
"no": "Universell utforming revisjon", "en-ie": "Accessibility Audit", "pl": "Audyt dostępności"
},
}
def generate_page(market, use_case):
m = MARKETS[market]
lang = m["lang"]
# Hämta use case-namn på rätt språk
uc_names = USE_CASES[use_case]
uc_name = uc_names.get(lang, uc_names.get("en-gb", use_case.replace("-", " ").title()))
# Skapa katalog
dir_path = os.path.join(BASE_DIR, market, use_case)
os.makedirs(dir_path, exist_ok=True)
# Generera HTML
html = f"""<!DOCTYPE html>
<html lang="{lang}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>{uc_name} — quiXzoom | {m['country']}</title>
<meta name="description" content="{uc_name} med quiXzoom i {m['country']}. Tjäna {m['pay']} per uppdrag. Betalt varje vecka.">
<meta name="geo.region" content="{m['code']}">
<meta name="geo.country" content="{m['country_en']}">
<meta name="language" content="{m['country']}">
<link rel="canonical" href="https://{m['domain']}/{use_case}/">
<style>
:root{{--qx-black:#0a0a0a;--qx-white:#fff;--qx-blue:#06f;--qx-gray:#f5f5f7;--qx-dark-gray:#1a1a1a}}
*{{margin:0;padding:0;box-sizing:border-box}}
body{{font-family:-apple-system,BlinkMacSystemFont,'SF Pro Display','Helvetica Neue',sans-serif;color:var(--qx-black);line-height:1.5}}
.hero{{background:var(--qx-black);color:var(--qx-white);padding:80px 20px;text-align:center}}
.hero h1{{font-size:2.5rem;margin-bottom:1rem}}
.hero p{{font-size:1.25rem;color:#ccc;margin-bottom:2rem}}
.badge{{display:inline-block;background:var(--qx-blue);color:#fff;padding:8px 16px;border-radius:20px;font-size:.875rem;margin-bottom:1rem}}
.container{{max-width:1200px;margin:0 auto;padding:40px 20px}}
.section{{padding:60px 20px}}
.section-gray{{background:var(--qx-gray)}}
.grid{{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:24px}}
.card{{background:#fff;padding:24px;border-radius:12px;box-shadow:0 2px 8px rgba(0,0,0,.1)}}
.card h3{{margin-bottom:.5rem}}
.cta{{display:inline-block;background:var(--qx-blue);color:#fff;padding:16px 32px;border-radius:8px;text-decoration:none;font-weight:600;margin-top:1rem}}
.footer{{background:var(--qx-dark-gray);color:#fff;padding:40px 20px;text-align:center}}
</style>
</head>
<body>
<div class="hero">
<div class="badge">{m['badge']}</div>
<h1>{uc_name}</h1>
<p>quiXzoom — Crowdsourcad datainsamling i {m['country']}. Tjäna {m['pay']} per uppdrag.</p>
<a href="https://app.quixzoom.com/join" class="cta">Bli Zoomer nu</a>
</div>
<div class="container">
<div class="section">
<h2>Hur det fungerar</h2>
<div class="grid">
<div class="card">
<h3>1. Hitta uppdrag</h3>
<p>Se tillgängliga {uc_name}-uppdrag nära dig i appen.</p>
</div>
<div class="card">
<h3>2. Dokumentera</h3>
<p>Följ instruktionerna och ta bilder med din smartphone.</p>
</div>
<div class="card">
<h3>3. Få betalt</h3>
<p>Betalt varje vecka. {m['pay']} per godkänt uppdrag.</p>
</div>
</div>
</div>
</div>
<div class="section section-gray">
<div class="container">
<h2>Varför quiXzoom?</h2>
<div class="grid">
<div class="card">
<h3>Flexibelt</h3>
<p>Jobba när du vill. Inga scheman, inga minimikrav.</p>
</div>
<div class="card">
<h3>Betalt snabbt</h3>
<p>Varje vecka direkt till ditt konto via Stripe.</p>
</div>
<div class="card">
<h3>Tillförlitligt</h3>
<p>Global plattform med verifierade uppdrag och tydlig feedback.</p>
</div>
</div>
</div>
</div>
<div class="footer">
<p>© 2026 quiXzoom AB — En del av <a href="https://aamos.systems" style="color:#fff">AAMOS</a></p>
<p>{m['domain']}</p>
</div>
</body>
</html>"""
filepath = os.path.join(dir_path, "index.html")
with open(filepath, 'w', encoding='utf-8') as f:
f.write(html)
return True
def main():
total = 0
done = 0
# Räkna totalt
for market in MARKETS:
for use_case in USE_CASES:
total += 1
print(f"Genererar {total} landningssidor...")
print()
# Generera alla sidor
for market in sorted(MARKETS.keys()):
print(f"=== Marknad: {market} ===")
for use_case in USE_CASES:
if generate_page(market, use_case):
done += 1
print()
print()
print(f"✅ Klart! {done} landningssidor genererade.")
print()
print("Nästa steg:")
print("1. Deploya till S3: aws s3 sync quixzoom-market-pages s3://quixzoom-landing-prod/markets/")
print("2. Invalida CloudFront-cache")
print("3. Verifiera att alla sidor är tillgängliga")
if __name__ == "__main__":
main()