Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-sitemap-i18n-fallback-routes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/sitemap': patch
---

Fixes i18n fallback pages missing from the generated sitemap when using `fallbackType: 'rewrite'`.
19 changes: 19 additions & 0 deletions .changeset/fix-sitemap-i18n-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
'astro': minor
---

Adds `fallbackRoutes` to the `IntegrationResolvedRoute` type, exposing i18n fallback routes to integrations via the `astro:routes:resolved` hook for projects using `fallbackType: 'rewrite'`.

This allows integrations such as the sitemap integration to properly include generated fallback routes in their output.

```js
{
'astro:routes:resolved': ({ routes }) => {
for (const route of routes) {
for (const fallback of route.fallbackRoutes) {
console.log(fallback.pathname) // e.g. /fr/about/
}
}
}
}
```
3 changes: 3 additions & 0 deletions packages/astro/src/integrations/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -703,5 +703,8 @@ export function toIntegrationResolvedRoute(
redirectRoute: route.redirectRoute
? toIntegrationResolvedRoute(route.redirectRoute, trailingSlash)
: undefined,
fallbackRoutes: route.fallbackRoutes.map((fallbackRoute) =>
toIntegrationResolvedRoute(fallbackRoute, trailingSlash),
),
};
}
5 changes: 5 additions & 0 deletions packages/astro/src/types/public/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,11 @@ export interface IntegrationResolvedRoute
*/
redirectRoute?: IntegrationResolvedRoute;

/**
* {@link RouteData.fallbackRoutes}
*/
fallbackRoutes: IntegrationResolvedRoute[];

/**
* @param {any} data The optional parameters of the route
*
Expand Down
19 changes: 14 additions & 5 deletions packages/integrations/sitemap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,12 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
return new URL(fullPath, finalSiteUrl).href;
});

const routeUrls = _routes.reduce<string[]>((urls, r) => {
// Only expose pages, not endpoints or redirects
if (r.type !== 'page') return urls;

const addRouteUrl = (urls: string[], r: IntegrationResolvedRoute): void => {
/**
* Dynamic URLs have entries with `undefined` pathnames
*/
if (r.pathname) {
if (shouldIgnoreStatus(r.pathname ?? r.pattern)) return urls;
if (shouldIgnoreStatus(r.pathname ?? r.pattern)) return;

// `finalSiteUrl` may end with a trailing slash
// or not because of base paths.
Expand All @@ -154,6 +151,18 @@ const createPlugin = (options?: SitemapOptions): AstroIntegration => {
urls.push(newUrl);
}
}
};

const routeUrls = _routes.reduce<string[]>((urls, r) => {
// Only expose pages, not endpoints or redirects
if (r.type !== 'page') return urls;

addRouteUrl(urls, r);

// Include i18n fallback routes (e.g. /fr/ falling back to /en/)
for (const fallbackRoute of (r.fallbackRoutes ?? [])) {
addRouteUrl(urls, fallbackRoute);
}

return urls;
}, []);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sitemap from '@astrojs/sitemap';
import { defineConfig } from 'astro/config';

export default defineConfig({
integrations: [sitemap()],
site: 'http://example.com',
i18n: {
locales: ['en', 'fr'],
defaultLocale: 'en',
fallback: {
fr: 'en',
},
routing: {
prefixDefaultLocale: false,
fallbackType: 'rewrite',
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "@test/sitemap-i18n-fallback",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*",
"@astrojs/sitemap": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
---
<html>
<head><title>About</title></head>
<body><h1>About</h1></body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
---
<html>
<head><title>Home</title></head>
<body><h1>Home</h1></body>
</html>
29 changes: 29 additions & 0 deletions packages/integrations/sitemap/test/i18n-fallback.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
import { loadFixture, readXML } from './test-utils.js';

describe('i18n fallback', () => {
/** @type {import('./test-utils.js').Fixture} */
let fixture;
/** @type {string[]} */
let urls;

before(async () => {
fixture = await loadFixture({
root: './fixtures/i18n-fallback/',
});
await fixture.build();
const data = await readXML(fixture.readFile('/sitemap-0.xml'));
urls = data.urlset.url.map((url) => url.loc[0]);
});

it('includes default locale pages', async () => {
assert.equal(urls.includes('http://example.com/'), true);
assert.equal(urls.includes('http://example.com/about/'), true);
});

it('includes fallback locale pages', async () => {
assert.equal(urls.includes('http://example.com/fr/'), true);
assert.equal(urls.includes('http://example.com/fr/about/'), true);
});
});
9 changes: 9 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading