Four follow-up defects found beyond the 2026-10-27 SEO audit (no copy changes):
1. legal.html canonical was https://ODOO4projects.com/legal — uppercase host AND a
path that 404s. Now https://odoo4projects.com/legal.html. The file's og:url keeps
its path /legal but its host is lowercased (path fix awaiting a decision).
2. The no-"4" domain typo in reader-visible <pre><code> body text of
blog/posts/{guide-migrate-enterprise,speed-run-deploy,my-first-post}.html:
odooprojects.com -> odoo4projects.com. Domain string only, no other wording.
3. Lowercase host in every machine-read value: the robots.txt Sitemap line, the
homepage + de/ + es/ Organization JSON-LD url / contactPoint.url / offers[].url,
legal.html og:url, and the four absolute self-URL hrefs in blog posts,
odoo/support.html and email/trial-confirmation.html. Display text untouched
(support@ODOO4projects.com stays as written).
4. One BlogPosting per blog post (15), every value taken from the page itself:
headline = its <h1>, datePublished = its visible post-meta date, url = its own
canonical, author/publisher = the Organization the site already publishes,
image = its og:image where one exists (omitted on the 10 posts that have none).
Empire ">950.00", FAQPage on support.html, the blog-chrome change and the bootcamp
date conflict are untouched — decisions pending with the user.
The translated pages now carry the same four footer items as the three English pages:
ODOO Bootcamp -> /odoo-erp-automation-bootcamp/, ODOO Hosting in 2027 (DE) / ODOO Hosting en
2027 (ES), Support/Soporte, Rechtliches/Aviso legal. Deleted: Startseite/Inicio,
Datenschutz/Privacidad, AGB/Terminos, Kontakt/Contactenos.
Rebuilt with work/i18n/build-i18n.py from the translator's six files (work/i18n/I18N-BUILD-PLAN.md
section 5), then: place-hero-slot.py for de|es/index.html, place-slot.py for the two 2027 pages,
insert-hero-i18n.py for the two bootcamp pages (the hero CSS is language-neutral chrome held
outside the translated source). Nothing else changed: git diff 31c02b1 over these six files is
the footer list and nothing else - bootcamp hero, three buy forms (product_id 12), 465.00,
selector and hreflang clusters untouched.
Checked: verify-html.py PROBLEMS: 0; node --check static/lang.js OK; verify-footer-useful-links-de-es.py
PROBLEMS: 0; test-build.py 88/88; test-lang.js 31/31; check-links.py BROKEN/MISPLACED: 0;
impeccable detector identical finding set on all six pages (0 changed lines).
The EN | DE | ES switcher existed but rendered into the footer slot, so a
visitor had to scroll to the bottom of the page to find it (measured live:
y=5582 on /, y=5498 on /odoo-erp-automation-bootcamp/). The user asked for a
selector a visitor can actually see.
- index.html, de/index.html, es/index.html: the slot is now the first child of
.hero .container, right-aligned in flow above the kicker. In flow, not a
fixed pill, so it cannot collide with the absolute .hero-notice.
- odoo-erp-automation-bootcamp/index.html: the slot is now the last child of
.bc-topbar .container, right of the nav links, behind a hairline brass
divider; .bc-topbar-links gets margin-left:auto so the brand stays left.
- One [data-lang-switcher] per page; the footer slot is removed everywhere.
- Styling follows the CI: Inter 12px / .06em / uppercase codes (the existing
.lang-switch rules), active language in --brass on these midnight surfaces,
the other two in the surrounding text colour. CSS-only, in each page's
inline <style>; lang.js is untouched, so its redirect behaviour is unchanged.
- The rules are recorded in work/i18n/I18N-BUILD-PLAN.md §3 for the phase-2
pages (de|es/odoo-hosting-2027.html, de|es/support.html).
Homepage pilot of the website i18n project. Adds the translated homepage for DE and
ES, the shared selector at /static/lang.js, and the hreflang cluster on all three
language versions (EN included, or the cluster is asymmetric and ignored).
- de/index.html, es/index.html: translator output plus the i18n build (html lang,
self-referencing canonical, hreflang cluster, lang.js tag, switcher slot in the footer).
- index.html: same cluster + lang.js tag + switcher slot; canonical and og:url
normalised to the lowercase host.
- static/lang.js: the tested selector (client-side language choice, auto-detect on the
EN homepage only, once per session; a stored choice or ?lang= always wins).
- sitemap.xml: /de/ and /es/ (priority 1.0, lastmod 2026-10-24).
- llms.txt: new '## Languages' section.
Two gaps in the build recipe were closed while building: a mirrored page cannot use
root-relative source paths (style.css, images/* would resolve to /de/style.css -> 404),
so the build now re-points assets at the site root and keeps page links on the EN route
until the language page exists; and og:url is now this page's own URL instead of the
EN one inherited from the source. Not built yet: support.html, odoo-hosting-2027.html,
the blog, the bootcamp page, the legal pages.