File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -73,13 +73,15 @@ export default defineConfig({
7373 icon ( ) ,
7474 react ( ) ,
7575 sitemap ( {
76- // Only the canonical /<locale>/… URLs belong in the sitemap. The catch-all
76+ // Only the canonical URLs belong in the sitemap. The catch-all
7777 // `[...path].astro` also emits `noindex` redirect stubs: language-less ones
78- // (e.g. `/guide/x`, `/` → `/en/` ) and per-locale ones for moved pages
78+ // (e.g. `/guide/x`) and per-locale ones for moved pages
7979 // (e.g. `/en/resources/middleware/csurf`). Exclude both.
8080 // Keep this locale list in sync with `i18n.locales` below.
8181 filter : ( page ) => {
8282 const { pathname } = new URL ( page ) ;
83+ // The homepage is served at `/` and is the canonical for `/en/`.
84+ if ( pathname === '/' ) return true ;
8385 if ( ! / ^ \/ ( d e | e n | e s | f r | i t | j a | k o | p t - b r | z h - c n | z h - t w ) ( \/ | $ ) / . test ( pathname ) ) return false ;
8486 const unlocalized = pathname . replace ( / ^ \/ [ a - z - ] + / , '' ) . replace ( / \/ $ / , '' ) ;
8587 return ! movedPagePaths . has ( unlocalized ) ;
Original file line number Diff line number Diff line change 1+ ---
2+ import { Hero , Features , AnnouncementBar } from ' @components/patterns' ;
3+ import { Card , Col } from ' @components/primitives' ;
4+ import Layout from ' @layouts/Layout.astro' ;
5+ import { getHomePath , getLangFromUrl , useTranslations } from ' @i18n/utils' ;
6+
7+ const lang = getLangFromUrl (Astro .url );
8+ const t = useTranslations (lang );
9+ const canonicalPathname = getHomePath (lang );
10+ ---
11+
12+ <Layout canonicalPathname ={ canonicalPathname } >
13+ <AnnouncementBar />
14+ <Hero />
15+ <Features title ={ t (' features.title' )} >
16+ <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
17+ <Card title ={ t (' features.webapplication.title' )} body ={ t (' features.webapplication.body' )} />
18+ </Col >
19+ <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
20+ <Card title ={ t (' features.api.title' )} body ={ t (' features.api.body' )} />
21+ </Col >
22+ <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
23+ <Card title ={ t (' features.performance.title' )} body ={ t (' features.performance.body' )} />
24+ </Col >
25+ <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
26+ <Card title ={ t (' features.middleware.title' )} body ={ t (' features.middleware.body' )} />
27+ </Col >
28+ </Features >
29+ </Layout >
Original file line number Diff line number Diff line change 66import { Body } from ' @components/primitives' ;
77import { Icon } from ' astro-icon/components' ;
88import type { BreadcrumbItem } from ' @utils/content' ;
9- import { getLangFromUrl , useTranslations } from ' @/i18n/utils' ;
9+ import { getHomePath , getLangFromUrl , useTranslations } from ' @/i18n/utils' ;
1010import ' ./Breadcrumbs.css' ;
1111
1212interface Props {
@@ -16,6 +16,7 @@ interface Props {
1616const { items } = Astro .props ;
1717const lang = getLangFromUrl (Astro .url );
1818const t = useTranslations (lang );
19+ const homeHref = getHomePath (lang );
1920---
2021
2122<nav aria-label ={ t (' nav.breadcrumb' )} >
@@ -24,7 +25,7 @@ const t = useTranslations(lang);
2425 <Body
2526 vMargin ={ false }
2627 as =" a"
27- href ={ ` /${ lang } ` }
28+ href ={ homeHref }
2829 class =" breadcrumb-link"
2930 aria-label ={ t (' nav.home' )}
3031 >
Original file line number Diff line number Diff line change @@ -10,10 +10,11 @@ import { Icon } from 'astro-icon/components';
1010import { Flex } from ' @/components/primitives' ;
1111import { ThemeSwitcher , SearchBox , LanguageSelect } from ' @components/patterns' ;
1212import { languagesArray } from ' @/i18n/locales' ;
13- import { getLangFromUrl , useTranslations } from ' @/i18n/utils' ;
13+ import { getHomePath , getLangFromUrl , useTranslations } from ' @/i18n/utils' ;
1414
1515const currentLang = getLangFromUrl (Astro .url );
1616const t = useTranslations (currentLang );
17+ const homeHref = getHomePath (currentLang );
1718---
1819
1920<header class =" header" >
@@ -30,7 +31,7 @@ const t = useTranslations(currentLang);
3031 <span class =" hamburger-line" ></span >
3132 <span class =" hamburger-line" ></span >
3233 </button >
33- <a href ={ ` /${ currentLang }/ ` } class =" logo-link" aria-label ={ t (' nav.home' )} >
34+ <a href ={ homeHref } class =" logo-link" aria-label ={ t (' nav.home' )} >
3435 <Image
3536 src =" /images/logos/express-kawaii.webp"
3637 alt =" Express.js kawaii logo"
Original file line number Diff line number Diff line change @@ -58,7 +58,8 @@ const options = languages.map((lang) => ({
5858 const currentPath = window.location.pathname;
5959 const newPath = replaceLanguageInPath(currentPath, code);
6060
61- window.location.href = newPath;
61+ // The English homepage is canonically served at `/`, not `/en/`.
62+ window.location.href = newPath === '/en/' ? '/' : newPath;
6263 }) as EventListener);
6364 });
6465 }
Original file line number Diff line number Diff line change @@ -6,7 +6,7 @@ import { Body } from '@/components/primitives';
66import { Image } from ' astro:assets' ;
77import { Icon } from ' astro-icon/components' ;
88import { VersionSwitcher } from ' @/components/patterns' ;
9- import { useTranslations } from ' @/i18n/utils' ;
9+ import { getHomePath , useTranslations } from ' @/i18n/utils' ;
1010import { DEFAULT_VERSION } from ' @/config/versions' ;
1111import SidebarItemsList from ' ./SidebarItemsList.astro' ;
1212import {
@@ -78,7 +78,7 @@ const commonItemsListProps = {
7878 <nav class =" sidebar-nav" aria-label ={ t (' nav.mainNavigation' )} >
7979 <ul class =" sidebar-nav-list" >
8080 <li class =" sidebar-logo-item" >
81- <a href ={ ` /${ lang }/ ` } class =" logo-link sidebar-nav-item" aria-label ={ t (' nav.home' )} >
81+ <a href ={ getHomePath ( lang ) } class =" logo-link sidebar-nav-item" aria-label ={ t (' nav.home' )} >
8282 <Image
8383 src =" /images/logos/express-kawaii.webp"
8484 alt =" Express.js kawaii logo"
Original file line number Diff line number Diff line change @@ -22,6 +22,13 @@ export function useTranslations(lang: keyof typeof ui) {
2222 return getNestedValue ( ui [ lang ] , key ) ?? getNestedValue ( ui [ defaultLang ] , key ) ?? key ;
2323 } ;
2424}
25+ /**
26+ * Homepage path for a language. English is served at the root.
27+ */
28+ export function getHomePath ( lang : string ) : string {
29+ return lang === defaultLang ? '/' : `/${ lang } /` ;
30+ }
31+
2532/**
2633 * Create a regex pattern to match language prefixes in URLs
2734 */
Original file line number Diff line number Diff line change @@ -100,18 +100,21 @@ const lang = getLangFromUrl(Astro.url);
100100
101101 {
102102 ! isBlogOrApi &&
103- [' x-default' , ... languageCodes ].map ((altLang ) => (
104- <link
105- rel = " alternate"
106- hreflang = { altLang }
107- href = {
108- new URL (
109- replaceLanguageInPath (canonicalPath , altLang === ' x-default' ? ' en' : altLang ),
110- Astro .site || Astro .url .origin
111- )
112- }
113- />
114- ))
103+ [' x-default' , ... languageCodes ].map ((altLang ) => {
104+ let altPath = replaceLanguageInPath (
105+ canonicalPath ,
106+ altLang === ' x-default' ? ' en' : altLang
107+ );
108+ // The English homepage is canonically served at `/`, not `/en/`.
109+ if (altPath === ' /en/' ) altPath = ' /' ;
110+ return (
111+ <link
112+ rel = " alternate"
113+ hreflang = { altLang }
114+ href = { new URL (altPath , Astro .site || Astro .url .origin )}
115+ />
116+ );
117+ })
115118 }
116119
117120 <title >{ pageTitle } </title >
Original file line number Diff line number Diff line change @@ -95,6 +95,8 @@ if (fallback) {
9595} else {
9696 target = ` /en/${slug } ` ;
9797}
98+ // The English homepage is canonically served at `/`, not `/en/`.
99+ if (target === ' /en/' ) target = ' /' ;
98100const canonical = new URL (target , Astro .site ).href ;
99101---
100102
Original file line number Diff line number Diff line change 11---
2- import { Hero , Features , AnnouncementBar } from ' @components/patterns' ;
3- import { Card , Col } from ' @components/primitives' ;
4- import Layout from ' @layouts/Layout.astro' ;
2+ import HomePage from ' @components/HomePage.astro' ;
53import { languageCodes } from ' @i18n/locales' ;
6- import { getLangFromUrl , useTranslations } from ' @i18n/utils' ;
74
85export function getStaticPaths() {
96 return languageCodes .map ((lang ) => ({
107 params: { lang },
118 }));
129}
13-
14- const lang = getLangFromUrl (Astro .url );
15- const t = useTranslations (lang );
1610---
1711
18- <Layout >
19- <AnnouncementBar />
20- <Hero />
21- <Features title ={ t (' features.title' )} >
22- <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
23- <Card title ={ t (' features.webapplication.title' )} body ={ t (' features.webapplication.body' )} />
24- </Col >
25- <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
26- <Card title ={ t (' features.api.title' )} body ={ t (' features.api.body' )} />
27- </Col >
28- <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
29- <Card title ={ t (' features.performance.title' )} body ={ t (' features.performance.body' )} />
30- </Col >
31- <Col xs ={ 12 } md ={ 6 } lg ={ 6 } class =" features__card-col" >
32- <Card title ={ t (' features.middleware.title' )} body ={ t (' features.middleware.body' )} />
33- </Col >
34- </Features >
35- </Layout >
12+ <HomePage />
You can’t perform that action at this time.
0 commit comments