Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .github/workflows/qa.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ jobs:
kern/ \
technology/ \
references/ \
company/ \
includes/nav.html \
includes/footer.html

Expand All @@ -93,13 +94,16 @@ jobs:
echo "::error file=$file::Missing meta description"
missing=$((missing + 1))
fi
done < <(find index.html kern/ technology/ references/ -name "*.html")
done < <(find index.html kern/ technology/ references/ \
company/about-us.html company/career.html \
company/get-in-touch.html company/media.html company/news.html \
-name "*.html" 2>/dev/null)

if [ "$missing" -gt 0 ]; then
echo "::error::$missing page(s) missing <meta name=\"description\">"
exit 1
fi
echo "All KERN pages have meta descriptions ✓"
echo "All pages have meta descriptions ✓"

# ── 6. Image size budget ────────────────────────────────────────────────────
images:
Expand Down
58 changes: 56 additions & 2 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
ROOT = Path(__file__).parent
TEMPLATES_DIR = ROOT / "templates"
LOCALES_DIR = ROOT / "locales"
BASE_URL = "https://riddleandcode.com"

# Maps language code → output directory
LANGS = {
Expand All @@ -32,6 +33,56 @@
}


def get_canonical_url(tmpl_path: Path) -> str | None:
"""Return the canonical EN URL for a template, or None for partials."""
rel = str(tmpl_path.relative_to(TEMPLATES_DIR)).replace("\\", "/")
if rel.startswith("includes/"):
return None
if rel == "index.html":
return f"{BASE_URL}/"
if rel.endswith("/index.html"):
return f"{BASE_URL}/{rel[:-len('index.html')]}"
return f"{BASE_URL}/{rel}"


def build_sitemap() -> None:
"""Generate sitemap.xml with bilingual hreflang annotations."""
templates = sorted(TEMPLATES_DIR.rglob("*.html"))
entries = []
for tmpl_path in templates:
en_url = get_canonical_url(tmpl_path)
if en_url is None:
continue
rel = str(tmpl_path.relative_to(TEMPLATES_DIR)).replace("\\", "/")
if rel == "index.html":
de_url = f"{BASE_URL}/de/"
elif rel.endswith("/index.html"):
de_url = f"{BASE_URL}/de/{rel[:-len('index.html')]}"
else:
de_url = f"{BASE_URL}/de/{rel}"

for loc in (en_url, de_url):
entries.append(
f" <url>\n"
f" <loc>{loc}</loc>\n"
f" <xhtml:link rel=\"alternate\" hreflang=\"en\" href=\"{en_url}\"/>\n"
f" <xhtml:link rel=\"alternate\" hreflang=\"de\" href=\"{de_url}\"/>\n"
f" <xhtml:link rel=\"alternate\" hreflang=\"x-default\" href=\"{en_url}\"/>\n"
f" </url>"
)

xml = (
'<?xml version="1.0" encoding="UTF-8"?>\n'
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"\n'
' xmlns:xhtml="http://www.w3.org/1999/xhtml">\n'
+ "\n".join(entries)
+ "\n</urlset>\n"
)
out = ROOT / "sitemap.xml"
out.write_text(xml, encoding="utf-8")
print(f" [sitemap] → sitemap.xml ({len(entries)} URLs)")


def render(template: str, strings: dict) -> str:
"""Replace {{ key }} placeholders with values from strings dict."""
def replace(m):
Expand Down Expand Up @@ -73,7 +124,8 @@ def build() -> int:
source = tmpl_path.read_text(encoding="utf-8")

for lang, out_dir in LANGS.items():
strings = {**locales[lang], "lang": lang}
canonical = get_canonical_url(tmpl_path)
strings = {**locales[lang], "lang": lang, "canonical_url": canonical or ""}
rendered = render(source, strings)

out_path = out_dir / rel
Expand All @@ -83,6 +135,7 @@ def build() -> int:
print(f" [{lang}] {rel} → {out_path.relative_to(ROOT)}")
built += 1

build_sitemap()
return built


Expand All @@ -97,7 +150,8 @@ def check_mode():
source = tmpl_path.read_text(encoding="utf-8")

for lang, real_dir in LANGS.items():
strings = {**locales[lang], "lang": lang}
canonical = get_canonical_url(tmpl_path)
strings = {**locales[lang], "lang": lang, "canonical_url": canonical or ""}
rendered = render(source, strings)
real_file = real_dir / rel

Expand Down
2 changes: 2 additions & 0 deletions company/about-us.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="About Riddle&amp;Code — Infrastructure for Distributed Energy"/>
<meta property="og:description" content="Riddle&amp;Code builds KERN — the infrastructure platform for distributed energy management. Serving utilities, aggregators, and communities across Europe."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/about-us.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/about-us.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/about-us.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/about-us.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/about-us.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions company/career.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Career — Riddle&amp;Code"/>
<meta property="og:description" content="Join the team building KERN — the infrastructure platform for distributed energy. Work on hard problems that matter for the energy transition."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/career.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/career.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/career.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/career.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/career.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions company/get-in-touch.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Contact — KERN by Riddle&amp;Code"/>
<meta property="og:description" content="Book a demo, arrange a site visit, or discuss how KERN fits into your infrastructure. We're here to help."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/get-in-touch.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/get-in-touch.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions company/media.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Media — Riddle&amp;Code"/>
<meta property="og:description" content="Press kit, brand logos, image materials and media contact for Riddle&amp;Code and KERN."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/media.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/media.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/media.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/media.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/media.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions company/news.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="News — Riddle&amp;Code"/>
<meta property="og:description" content="Latest news, research and updates from Riddle&amp;Code and the KERN team."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/news.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/news.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/news.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/news.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/news.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
<style>
Expand Down
1 change: 1 addition & 0 deletions cspell.de.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
"Zertifikatsbasierte",
"Zigbee",
"zigbee",
"zweckentwickelte",
"zweckgebaut"
]
}
2 changes: 2 additions & 0 deletions de/company/about-us.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Über Riddle&amp;Code — Infrastruktur für verteilte Energie"/>
<meta property="og:description" content="Riddle&amp;Code baut KERN — die Infrastrukturplattform für verteiltes Energiemanagement. Für Energieversorger, Aggregatoren und Gemeinschaften in ganz Europa."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/about-us.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/about-us.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/about-us.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/about-us.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/about-us.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions de/company/career.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Karriere — Riddle&amp;Code"/>
<meta property="og:description" content="Werden Sie Teil des Teams, das KERN aufbaut — die Infrastrukturplattform für verteilte Energie."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/career.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/career.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/career.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/career.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/career.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions de/company/get-in-touch.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Kontakt — KERN by Riddle&amp;Code"/>
<meta property="og:description" content="Demo buchen, Besuch der Live-Referenzanlage vereinbaren oder besprechen, wie KERN in Ihre Infrastruktur passt."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/get-in-touch.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/get-in-touch.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/get-in-touch.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions de/company/media.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Medien — Riddle&amp;Code"/>
<meta property="og:description" content="Pressemappe, Markenlogos, Bildmaterial und Medienkontakt für Riddle&amp;Code und KERN."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/media.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/media.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/media.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/media.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/media.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
</head>
Expand Down
2 changes: 2 additions & 0 deletions de/company/news.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<meta property="og:title" content="Neuigkeiten — Riddle&amp;Code"/>
<meta property="og:description" content="Aktuelle Neuigkeiten, Forschung und Updates vom Riddle&amp;Code- und KERN-Team."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/company/news.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/company/news.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/company/news.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/company/news.html"/>
<link rel="canonical" href="https://riddleandcode.com/company/news.html"/>
<link href="/styles/main.css" rel="stylesheet" type="text/css"/>
<script src="/scripts/main.js" defer></script>
<style>
Expand Down
46 changes: 46 additions & 0 deletions de/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,55 @@
<meta property="og:description" content="R&amp;C KERN prognostiziert, steuert und liefert Flexibilität hinter dem Zähler autonom."/>
<meta property="og:image" content="/images/6401f477a5a79419a904f904_r&amp;c_mypwr.jpg"/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/"/>
<link rel="canonical" href="https://riddleandcode.com/"/>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@graph": [
{
"@type": "Organization",
"@id": "https://riddleandcode.com/#org",
"name": "Riddle&Code",
"url": "https://riddleandcode.com",
"description": "Infrastructure for distributed energy. KERN autonomously forecasts, dispatches and delivers flexibility behind the meter for aggregators, utilities and energy communities.",
"address": {
"@type": "PostalAddress",
"addressLocality": "Vienna",
"addressCountry": "AT"
},
"contactPoint": {
"@type": "ContactPoint",
"email": "office@riddleandcode.com",
"contactType": "sales"
}
},
{
"@type": "WebSite",
"@id": "https://riddleandcode.com/#website",
"url": "https://riddleandcode.com",
"name": "Riddle&Code",
"publisher": {"@id": "https://riddleandcode.com/#org"},
"inLanguage": ["en", "de"]
},
{
"@type": "SoftwareApplication",
"name": "KERN",
"applicationCategory": "EnergyManagementSoftware",
"description": "Autonomous energy management platform for behind-the-meter flexibility — forecasting, dispatching and confirming distributed energy assets for aggregators, utilities and energy communities.",
"provider": {"@id": "https://riddleandcode.com/#org"},
"url": "https://riddleandcode.com/kern/",
"offers": {
"@type": "Offer",
"description": "B2B SaaS platform for energy utilities, aggregators, VPP platforms and energy communities"
}
}
]
}
</script>
<link rel="stylesheet" href="/styles/main.css">
<script src="/scripts/main.js" defer></script>
<style>
Expand Down
6 changes: 6 additions & 0 deletions de/kern/for-aggregators.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<title>KERN für Aggregatoren — Riddle&amp;Code</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="description" content="Sichern Sie Ihre Flexibilitätsgebote jedes Mal ab. KERN steuert und bestätigt die Ausführung hinter dem Zähler autonom — ohne manuelle Eingriffe, ohne Pönalen."/>
<meta property="og:title" content="KERN für Aggregatoren — Riddle&amp;Code"/>
<meta property="og:description" content="Sichern Sie Ihre Flexibilitätsgebote jedes Mal ab. KERN steuert und bestätigt die Ausführung hinter dem Zähler autonom — ohne manuelle Eingriffe, ohne Pönalen."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/kern/for-aggregators.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/kern/for-aggregators.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/kern/for-aggregators.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/kern/for-aggregators.html"/>
<link rel="canonical" href="https://riddleandcode.com/kern/for-aggregators.html"/>
<link rel="stylesheet" href="/styles/main.css">
<script src="/scripts/main.js" defer></script>
<style>
Expand Down
6 changes: 6 additions & 0 deletions de/kern/for-communities.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
<title>KERN für Energiegemeinschaften — Riddle&amp;Code</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="description" content="Maximieren Sie den gemeinsamen Eigenverbrauch automatisch. KERN optimiert jedes Asset in der Gemeinschaft und verbindet kollektive Flexibilität mit Märkten."/>
<meta property="og:title" content="KERN für Energiegemeinschaften — Riddle&amp;Code"/>
<meta property="og:description" content="Maximieren Sie den gemeinsamen Eigenverbrauch automatisch. KERN optimiert jedes Asset in der Gemeinschaft und verbindet kollektive Flexibilität mit Märkten."/>
<meta property="og:type" content="website"/>
<meta property="og:url" content="https://riddleandcode.com/kern/for-communities.html"/>
<meta name="twitter:card" content="summary_large_image"/>
<link rel="alternate" hreflang="en" href="https://riddleandcode.com/kern/for-communities.html"/>
<link rel="alternate" hreflang="de" href="https://riddleandcode.com/de/kern/for-communities.html"/>
<link rel="alternate" hreflang="x-default" href="https://riddleandcode.com/kern/for-communities.html"/>
<link rel="canonical" href="https://riddleandcode.com/kern/for-communities.html"/>
<link rel="stylesheet" href="/styles/main.css">
<script src="/scripts/main.js" defer></script>
<style>
Expand Down
Loading
Loading