@@ -4,6 +4,22 @@ const TRANSLATIONS = { it };
44const LANG_PREFIXES = Object . keys ( TRANSLATIONS ) ;
55const 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 = / b o t | c r a w l | s p i d e r | s l u r p | f a c e b o o k e x t e r n a l h i t | l i n k e d i n b o t | t w i t t e r b o t | w h a t s a p p | t e l e g r a m | e m b e d l y | q u o r a | p i n t e r e s t | r e d d i t b o t | a p p l e b o t | y a n d e x | d u c k d u c k b o t | b a i d u s p i d e r | s o g o u | s e m r u s h | a h r e f s | m j 1 2 b o t | d o t b o t | p e t a l b o t | b y t e s p i d e r | g p t b o t | c h a t g p t | a n t h r o p i c | c l a u d e | p e r p l e x i t y / 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+
723export 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 }
0 commit comments