Skip to content

Commit 441f8a6

Browse files
paoloanznclaude
andcommitted
feat: auto-detect Italian visitors via Accept-Language header
Replace manual language switcher button with automatic detection. Worker now checks Accept-Language header and 302 redirects Italian visitors to /it/ pages. Bots are excluded so both versions get indexed. Added run_worker_first to ensure worker processes all requests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d54fb2e commit 441f8a6

7 files changed

Lines changed: 31 additions & 51 deletions

File tree

index.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979
<button class="nav-cta nav-cta-mobile" data-i18n="nav.cta">View Ecosystem</button>
8080
</div>
8181
<button class="nav-cta nav-cta-desktop" data-i18n="nav.cta">View Ecosystem</button>
82-
<a href="/it/" class="lang-switch" id="langSwitch">IT</a>
8382
<button class="nav-toggle" aria-label="Menu">
8483
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
8584
<line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/>

src/main.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,3 @@ document.querySelectorAll('.nav-cta').forEach((btn) => {
120120
})
121121
})
122122

123-
// LANGUAGE SWITCHER
124-
const langSwitch = document.getElementById('langSwitch')
125-
if (langSwitch) {
126-
const isItalian = document.documentElement.lang === 'it'
127-
if (isItalian) {
128-
langSwitch.textContent = 'EN'
129-
langSwitch.href = window.location.pathname.replace(/^\/it/, '') || '/'
130-
} else {
131-
langSwitch.href = '/it' + window.location.pathname
132-
}
133-
}

src/style.css

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,6 @@ nav.scrolled{
9292
box-shadow:0 0 20px rgba(62,207,142,0.3);
9393
transform:scale(1.03);
9494
}
95-
.lang-switch{
96-
font-size:11px;font-weight:500;letter-spacing:0.06em;
97-
color:var(--text-muted);text-decoration:none;
98-
padding:6px 10px;border:1px solid var(--border);border-radius:100px;
99-
transition:all 0.2s var(--ease);flex-shrink:0;
100-
margin-left:4px;
101-
}
102-
.lang-switch:hover{
103-
color:var(--text-primary);border-color:var(--border-hover);
104-
}
105-
10695
/* HERO */
10796
.hero{
10897
min-height:100vh;display:flex;flex-direction:column;

src/worker.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ const TRANSLATIONS = { it };
44
const LANG_PREFIXES = Object.keys(TRANSLATIONS);
55
const PAGE_PATHS = ['/', '/tools/n8n-cli/', '/tools/x-cli/'];
66

7+
// Bots that should NOT be auto-redirected (so they index both versions)
8+
const BOT_PATTERN = /bot|crawl|spider|slurp|facebookexternalhit|linkedinbot|twitterbot|whatsapp|telegram|embedly|quora|pinterest|redditbot|applebot|yandex|duckduckbot|baiduspider|sogou|semrush|ahrefs|mj12bot|dotbot|petalbot|bytespider|gptbot|chatgpt|anthropic|claude|perplexity/i;
9+
10+
function isBot(request) {
11+
const ua = request.headers.get('user-agent') || '';
12+
return BOT_PATTERN.test(ua);
13+
}
14+
15+
function prefersItalian(request) {
16+
const accept = request.headers.get('accept-language') || '';
17+
if (!accept) return false;
18+
// Parse first language in Accept-Language header
19+
const primary = accept.split(',')[0].trim().split(';')[0].trim();
20+
return primary.startsWith('it');
21+
}
22+
723
export default {
824
async fetch(request, env) {
925
const url = new URL(request.url);
@@ -22,16 +38,26 @@ export default {
2238
}
2339

2440
// Redirect /it to /it/
25-
if (pathname === `/${lang}`) {
41+
if (lang && pathname === `/${lang}`) {
2642
return Response.redirect(`${url.origin}/${lang}/`, 301);
2743
}
2844

29-
// No language prefix — serve English, inject hreflang on HTML
45+
// No language prefix — English page
3046
if (!lang) {
47+
// Auto-redirect Italian visitors to /it/ (skip bots)
48+
if (!isBot(request) && prefersItalian(request)) {
49+
const italianUrl = `${url.origin}/it${pathname}${url.search}`;
50+
return new Response(null, {
51+
status: 302,
52+
headers: { 'Location': italianUrl, 'Vary': 'Accept-Language' },
53+
});
54+
}
55+
3156
const response = await env.ASSETS.fetch(request);
3257
const ct = response.headers.get('content-type') || '';
3358
if (!ct.includes('text/html')) return response;
3459

60+
// Inject hreflang tags into English pages
3561
return new HTMLRewriter()
3662
.on('head', new HreflangInjector(pathname))
3763
.transform(response);
@@ -67,6 +93,7 @@ export default {
6793

6894
const headers = new Headers(transformed.headers);
6995
headers.set('Content-Language', lang);
96+
headers.set('Vary', 'Accept-Language');
7097

7198
return new Response(transformed.body, {
7299
status: transformed.status,
@@ -119,7 +146,6 @@ class HeadTransformer {
119146
this.translations = translations;
120147
}
121148
element(el) {
122-
// Inject hreflang tags
123149
el.append(
124150
`\n<link rel="alternate" hreflang="en" href="https://gladium.ai${this.path}">`,
125151
{ html: true }

tools/n8n-cli/index.html

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
<button class="nav-cta nav-cta-mobile" data-i18n="nav.cta" onclick="window.location.href='/#open-source'">View Ecosystem</button>
6262
</div>
6363
<button class="nav-cta nav-cta-desktop" data-i18n="nav.cta" onclick="window.location.href='/#open-source'">View Ecosystem</button>
64-
<a href="/it/" class="lang-switch" id="langSwitch">IT</a>
6564
<button class="nav-toggle" aria-label="Menu">
6665
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
6766
<line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/>
@@ -378,17 +377,6 @@ <h4 data-i18n="tool.footer.opensource">Open Source</h4>
378377
)
379378
reveals.forEach((el) => observer.observe(el))
380379

381-
// LANGUAGE SWITCHER
382-
const langSwitch = document.getElementById('langSwitch')
383-
if (langSwitch) {
384-
const isItalian = document.documentElement.lang === 'it'
385-
if (isItalian) {
386-
langSwitch.textContent = 'EN'
387-
langSwitch.href = window.location.pathname.replace(/^\/it/, '') || '/'
388-
} else {
389-
langSwitch.href = '/it' + window.location.pathname
390-
}
391-
}
392380
</script>
393381
</body>
394382
</html>

tools/x-cli/index.html

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@
6161
<button class="nav-cta nav-cta-mobile" data-i18n="nav.cta" onclick="window.location.href='/#open-source'">View Ecosystem</button>
6262
</div>
6363
<button class="nav-cta nav-cta-desktop" data-i18n="nav.cta" onclick="window.location.href='/#open-source'">View Ecosystem</button>
64-
<a href="/it/" class="lang-switch" id="langSwitch">IT</a>
6564
<button class="nav-toggle" aria-label="Menu">
6665
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
6766
<line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/>
@@ -378,17 +377,6 @@ <h4 data-i18n="tool.footer.opensource">Open Source</h4>
378377
)
379378
reveals.forEach((el) => observer.observe(el))
380379

381-
// LANGUAGE SWITCHER
382-
const langSwitch = document.getElementById('langSwitch')
383-
if (langSwitch) {
384-
const isItalian = document.documentElement.lang === 'it'
385-
if (isItalian) {
386-
langSwitch.textContent = 'EN'
387-
langSwitch.href = window.location.pathname.replace(/^\/it/, '') || '/'
388-
} else {
389-
langSwitch.href = '/it' + window.location.pathname
390-
}
391-
}
392380
</script>
393381
</body>
394382
</html>

wrangler.jsonc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"main": "src/worker.js",
66
"assets": {
77
"directory": "./dist",
8-
"binding": "ASSETS"
8+
"binding": "ASSETS",
9+
"run_worker_first": true
910
}
1011
}

0 commit comments

Comments
 (0)