Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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'`
Comment thread
yanthomasdev marked this conversation as resolved.
Outdated
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