i18n phase 2: publish DE + ES for odoo-hosting-2027.html and support.html

Four new pages, built from the verified translator output with work/i18n/build-i18n.py,
plus the same hreflang cluster and top-bar language selector on the two English pages.
Same recipe as the homepage pilot (main 937dbd4 / 06beab4); nothing else touched.

- de|es/odoo-hosting-2027.html, de|es/support.html: per-language canonical, the full
  hreflang cluster (en-US, de, es, x-default -> EN), /static/lang.js, and the switcher
  slot placed in the page's own top bar (.cmp-topbar on the 2027 page, .blog-header on
  support.html) with the per-shape CSS hook from I18N-BUILD-PLAN.md §3.
- odoo-hosting-2027.html, support.html: same cluster, same selector, so the cluster is
  symmetric (asymmetric hreflang is discarded by Google). support.html's canonical and
  og:url were still on the capitalised ODOO4projects.com host; the build normalises them
  to the lowercase form the rest of the site and sitemap.xml use.
- Internal links: the build's rebase step now also localises a root-absolute page link
  (/support.html#contact in the translator's 2027 pages) once that page exists in the
  language. /de/support.html, /de/odoo-hosting-2027.html, /de/, /de/#pricing and
  /de/#trialCard are local; /legal.html stays on the EN route because the legal pages
  are not translated (lawyer review pending).
- sitemap.xml: +4 URLs, lastmod 2026-10-24, priority reused from the EN entry (2027 -> 0.9,
  support.html -> 0.6 fallback, it has no EN entry). 17 -> 21 <loc>, no duplicates.
- llms.txt: the ## Languages section now names the mirrored pages.

Checks: verify-html.py PROBLEMS: 0; node --check static/lang.js OK; test-lang.js 31/31;
test-build.py 64/64 (was 43; +21 for the four built pages and the root-absolute rule);
check-links.py on the four new pages BROKEN/MISPLACED: 0.
This commit is contained in:
oliver committed 2026-10-24 21:56:08 +00:00
1 parent 0721804aab
commit b69e4ceaed
8 files changed
+3302 -4

No files matched your search

+30
View File
@@ -9,6 +9,10 @@
content="Odoo hosting in 2027, compared: managed Odoo Community from ODOO4projects against a self-managed VPS, odoo.sh, Odoo Online and your own hardware. One login, one yearly price, no per-user licence."
/>
<link rel="canonical" href="https://odoo4projects.com/odoo-hosting-2027.html" />
<link rel="alternate" hreflang="en-US" href="https://odoo4projects.com/odoo-hosting-2027.html" />
<link rel="alternate" hreflang="de" href="https://odoo4projects.com/de/odoo-hosting-2027.html" />
<link rel="alternate" hreflang="es" href="https://odoo4projects.com/es/odoo-hosting-2027.html" />
<link rel="alternate" hreflang="x-default" href="https://odoo4projects.com/odoo-hosting-2027.html" />
<meta property="og:title" content="Odoo Hosting 2027: Managed Odoo Community, Live in About Five Minutes" />
<meta
property="og:description"
@@ -77,6 +81,30 @@
color: var(--brass);
}
/* Language selector — slides into the top-bar row, right of the links, behind a hairline brass
divider. CI §1/§2: brass marks the active language; lang.js owns the markup. */
.cmp-topbar-links {
margin-left: auto;
}
.cmp-topbar .lang-switch-slot {
display: flex;
align-items: center;
padding-left: 1rem;
border-left: 1px solid rgba(201, 162, 39, 0.45);
}
.cmp-topbar .lang-switch {
color: rgba(255, 255, 255, 0.7);
}
.cmp-topbar .lang-switch a:hover,
.cmp-topbar .lang-switch a:focus-visible {
color: var(--brass-bright);
}
.cmp-topbar .lang-switch a[aria-current="true"] {
color: var(--brass);
text-decoration: underline;
text-underline-offset: 3px;
}
/* Hero */
.cmp-hero {
min-height: 0;
@@ -532,6 +560,7 @@
window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}};
plausible.init()
</script>
<script defer src="/static/lang.js"></script>
</head>
<body>
<!-- Page-scoped top bar: the site has no global header, so the page carries its own way home. -->
@@ -542,6 +571,7 @@
<a href="index.html#pricing">Plans &amp; pricing</a>
<a href="support.html">Support</a>
</nav>
<div data-lang-switcher class="lang-switch-slot"></div>
</div>
</div>