From 70e6299280665c1249fc8497b11f1f43c5127d81 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger Date: Wed, 22 May 2024 09:00:26 -0300 Subject: [PATCH 01/10] [testing.mdx] restructure page with test types as headings (#8367) --- src/content/docs/en/guides/testing.mdx | 264 +++++++++++++------------ 1 file changed, 134 insertions(+), 130 deletions(-) diff --git a/src/content/docs/en/guides/testing.mdx b/src/content/docs/en/guides/testing.mdx index 5d99c68c5102c..bf116f687af9b 100644 --- a/src/content/docs/en/guides/testing.mdx +++ b/src/content/docs/en/guides/testing.mdx @@ -10,7 +10,9 @@ Testing helps you write and maintain working Astro code. Astro supports many pop Testing frameworks allow you to state **assertions** or **expectations** about how your code should behave in specific situations, then compare these to the actual behavior of your current code. -## Vitest +## Unit and integration tests + +### Vitest A Vite-native unit test framework with ESM, TypeScript and JSX support powered by esbuild. @@ -43,11 +45,132 @@ export default getViteConfig( See the [Astro + Vitest starter template](https://github.com/withastro/astro/tree/latest/examples/with-vitest) on GitHub. -## Cypress +## End-to-end tests + +### Playwright + +Playwright is an end-to-end testing framework for modern web apps. Use the Playwright API in JavaScript or TypeScript to test your Astro code on all modern rendering engines including Chromium, WebKit, and Firefox. + +#### Installation + +You can get started and run your tests using the [VS Code Extension](https://playwright.dev/docs/getting-started-vscode). + +Alternatively, you can install Playwright within your Astro project using the package manager of your choice. Follow the CLI steps to choose JavaScript/TypeScript, name your test folder, and add an optional GitHub Actions workflow. + + + + ```shell + npm init playwright@latest + ``` + + + ```shell + pnpm dlx create-playwright + ``` + + + ```shell + yarn create playwright + ``` + + + +#### Create your first Playwright test + + +1. Choose a page to test. This example will test the example page `index.astro` below. + + ```html title="src/pages/index.astro" + --- + --- + + + Astro is awesome! + + + + + ``` + +2. Create a new folder and add the following test file in `src/test`. Copy and paste the following test into the file to verify that the page meta information is correct. Update the value of the page `` to match the page you are testing. + + ```jsx title="src/test/index.spec.ts" "Astro is awesome!" + import { test, expect } from '@playwright/test'; + + test('meta is correct', async ({ page }) => { + await page.goto("http://localhost:4321/"); + + await expect(page).toHaveTitle('Astro is awesome!'); + }); + ``` + + :::tip[Set a `baseUrl`] + You can set [`"baseURL": "http://localhost:4321"`](https://playwright.dev/docs/api/class-testoptions#test-options-base-url) in the `playwright.config.ts` configuration file to use `page.goto("/")` instead of `page.goto("http://localhost:4321/")` for a more convenient URL. + ::: +</Steps> + +#### Running your Playwright tests + +You can run a single test or several tests at once, testing one or multiple browsers. By default, your test results will be shown in the terminal. Optionally, you can open the HTML Test Reporter to show a full report and filter test results. + +<Steps> +1. To run our test from the previous example using the command line, use the `test` command. Optionally, include the file name to run just the single test: + + ```sh + npx playwright test index.spec.ts + ``` + +2. To see the full HTML Test Report, open it using the following command: + + ```sh + npx playwright show-report + ``` +</Steps> + +:::tip +Run your tests against your production code to more closely resemble your live, deployed site. +::: + +##### Advanced: Launching a development web server during the tests + +You can also have Playwright start your server when you run your testing script by using the [`webServer`](https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests) option in the Playwright configuration file. + +Here is an example of the configuration and commands required when using npm: + +<Steps> +1. Add a test script to your `package.json` file in the project root, such as `"test:e2e": "playwright test"`. + +2. In `playwright.config.ts`, add the `webServer` object and update the command value to `npm run preview`. + + ```js title="playwright.config.ts" ins={4-9} "npm run preview" + import { defineConfig } from '@playwright/test'; + + export default defineConfig({ + webServer: { + command: 'npm run preview', + url: 'http://localhost:4321/', + timeout: 120 * 1000, + reuseExistingServer: !process.env.CI, + }, + use: { + baseURL: 'http://localhost:4321/', + }, + }); + ``` + +3. Run `npm run build`, then run `npm run test:e2e` to run the Playwright tests. +</Steps> + +More information about Playwright can be found in the links below: + +- [Getting started with Playwright](https://playwright.dev/docs/intro) +- [Use a development server](https://playwright.dev/docs/test-webserver#configuring-a-web-server) + +### Cypress Cypress is a front-end testing tool built for the modern web. Cypress enables you to write end-to-end tests for your Astro site. -### Installation +#### Installation You can install Cypress using the package manager of your choice. @@ -71,7 +194,7 @@ You can install Cypress using the package manager of your choice. </Fragment> </PackageManagerTabs> -### Configuration +#### Configuration In the root of your project, create a `cypress.config.js` file with the following content: @@ -85,7 +208,7 @@ export default defineConfig({ }) ``` -### Create your first Cypress test +#### Create your first Cypress test <Steps> 1. Choose a page to test. This example will test the example page `index.astro` below. @@ -120,7 +243,7 @@ export default defineConfig({ ::: </Steps> -### Running your Cypress tests +#### Running your Cypress tests Cypress can be run from the command line or from the Cypress App. The App provides a visual interface for running and debugging your tests. @@ -163,18 +286,18 @@ To check that your test really does work, you can change the following line in t Then run the test again. You should see a red "x" in the output confirming that your test failed. ::: -### Next steps +#### Next steps More information about Cypress can be found in the links below: - [Introduction to Cypress](https://docs.cypress.io/guides/basics/introduction-to-cypress) - [Testing Your App](https://docs.cypress.io/guides/end-to-end-testing/testing-your-app) -## NightwatchJS +### NightwatchJS Nightwatch.js is a test automation framework with a powerful set of tools to write, run, and debug your tests across the web with built-in support for all major browsers and their mobile equivalents, as well as native mobile applications. -### Installation +#### Installation You can install NightwatchJS within your Astro project using the package manager of your choice. Follow the CLI steps to choose JavaScript/TypeScript, name your test folder, and select whether or not to include component testing and testing on mobile browsers. @@ -196,7 +319,7 @@ You can install NightwatchJS within your Astro project using the package manager </Fragment> </PackageManagerTabs> -### Create your first Nightwatch test +#### Create your first Nightwatch test <Steps> 1. Choose a page to test. This example will test the example page `index.astro` below. @@ -232,7 +355,7 @@ You can install NightwatchJS within your Astro project using the package manager ::: </Steps> -### Running your NightwatchJS tests +#### Running your NightwatchJS tests You can run a single test or several tests at once, testing one or multiple browsers. By default, your test results will be shown in the terminal. Optionally, you can open the HTML Test Reporter to show a full report and filter test results. @@ -264,122 +387,3 @@ More information about NightwatchJS can be found in the links below: - [Intro to Nightwatch](https://nightwatchjs.org/guide/overview/what-is-nightwatch.html) - [Testing with Nightwatch](https://nightwatchjs.org/guide/writing-tests/introduction.html) - -## Playwright - -Playwright is an end-to-end testing framework for modern web apps. Use the Playwright API in JavaScript or TypeScript to test your Astro code on all modern rendering engines including Chromium, WebKit, and Firefox. - -### Installation - -You can get started and run your tests using the [VS Code Extension](https://playwright.dev/docs/getting-started-vscode). - -Alternatively, you can install Playwright within your Astro project using the package manager of your choice. Follow the CLI steps to choose JavaScript/TypeScript, name your test folder, and add an optional GitHub Actions workflow. - -<PackageManagerTabs> - <Fragment slot="npm"> - ```shell - npm init playwright@latest - ``` - </Fragment> - <Fragment slot="pnpm"> - ```shell - pnpm dlx create-playwright - ``` - </Fragment> - <Fragment slot="yarn"> - ```shell - yarn create playwright - ``` - </Fragment> -</PackageManagerTabs> - -### Create your first Playwright test - -<Steps> -1. Choose a page to test. This example will test the example page `index.astro` below. - - ```html title="src/pages/index.astro" - --- - --- - <html lang="en"> - <head> - <title>Astro is awesome! - - - - - ``` - -2. Create a new folder and add the following test file in `src/test`. Copy and paste the following test into the file to verify that the page meta information is correct. Update the value of the page `` to match the page you are testing. - - ```jsx title="src/test/index.spec.ts" "Astro is awesome!" - import { test, expect } from '@playwright/test'; - - test('meta is correct', async ({ page }) => { - await page.goto("http://localhost:4321/"); - - await expect(page).toHaveTitle('Astro is awesome!'); - }); - ``` - - :::tip[Set a `baseUrl`] - You can set [`"baseURL": "http://localhost:4321"`](https://playwright.dev/docs/api/class-testoptions#test-options-base-url) in the `playwright.config.ts` configuration file to use `page.goto("/")` instead of `page.goto("http://localhost:4321/")` for a more convenient URL. - ::: -</Steps> - -### Running your Playwright tests - -You can run a single test or several tests at once, testing one or multiple browsers. By default, your test results will be shown in the terminal. Optionally, you can open the HTML Test Reporter to show a full report and filter test results. - -<Steps> -1. To run our test from the previous example using the command line, use the `test` command. Optionally, include the file name to run just the single test: - - ```sh - npx playwright test index.spec.ts - ``` - -2. To see the full HTML Test Report, open it using the following command: - - ```sh - npx playwright show-report - ``` -</Steps> - -:::tip -Run your tests against your production code to more closely resemble your live, deployed site. -::: - -#### Advanced: Launching a development web server during the tests - -You can also have Playwright start your server when you run your testing script by using the [`webServer`](https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests) option in the Playwright configuration file. - -Here is an example of the configuration and commands required when using npm: - -<Steps> -1. Add a test script to your `package.json` file in the project root, such as `"test:e2e": "playwright test"`. - -2. In `playwright.config.ts`, add the `webServer` object and update the command value to `npm run preview`. - - ```js title="playwright.config.ts" ins={4-9} "npm run preview" - import { defineConfig } from '@playwright/test'; - - export default defineConfig({ - webServer: { - command: 'npm run preview', - url: 'http://localhost:4321/', - timeout: 120 * 1000, - reuseExistingServer: !process.env.CI, - }, - use: { - baseURL: 'http://localhost:4321/', - }, - }); - ``` - -3. Run `npm run build`, then run `npm run test:e2e` to run the Playwright tests. -</Steps> - -More information about Playwright can be found in the links below: - -- [Getting started with Playwright](https://playwright.dev/docs/intro) -- [Use a development server](https://playwright.dev/docs/test-webserver#configuring-a-web-server) From 8a099352d3f7d1f380c0a3f1abca0380f92cb57d Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa <my.burning@gmail.com> Date: Wed, 22 May 2024 13:07:21 +0100 Subject: [PATCH 02/10] feat: container API docs (#8281) Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --- src/content/docs/en/guides/testing.mdx | 25 ++ .../docs/en/reference/container-reference.mdx | 295 ++++++++++++++++++ src/i18n/en/nav.ts | 5 + 3 files changed, 325 insertions(+) create mode 100644 src/content/docs/en/reference/container-reference.mdx diff --git a/src/content/docs/en/guides/testing.mdx b/src/content/docs/en/guides/testing.mdx index bf116f687af9b..b100dce6b95a1 100644 --- a/src/content/docs/en/guides/testing.mdx +++ b/src/content/docs/en/guides/testing.mdx @@ -5,6 +5,7 @@ i18nReady: true --- import { Steps } from '@astrojs/starlight/components'; import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'; +import Since from '~/components/Since.astro' Testing helps you write and maintain working Astro code. Astro supports many popular tools for unit tests, component tests, and end-to-end tests including Jest, Mocha, Jasmine, [Cypress](https://cypress.io) and [Playwright](https://playwright.dev). You can even install framework-specific testing libraries such as React Testing Library to test your UI framework components. @@ -45,6 +46,30 @@ export default getViteConfig( See the [Astro + Vitest starter template](https://github.com/withastro/astro/tree/latest/examples/with-vitest) on GitHub. +#### Vitest and Container API + +<Since v="4.9.0" /> + +You can natively test Astro components using the [container API](/en/reference/container-reference/). First, setup [`vitest` as explained above](#vitest), then create a `.test.js` file to test your component: + +```js +import { experimental_AstroContainer as AstroContainer } from 'astro/container'; +import { expect, test } from 'vitest'; +import Card from '../src/components/Card.astro'; + +test('Card with slots', async () => { + const container = await AstroContainer.create(); + const result = await container.renderToString(Card, { + slots: { + default: 'Card content', + }, + }); + + expect(result).toContain('This is a card'); + expect(result).toContain('Card content'); +}); +``` + ## End-to-end tests ### Playwright diff --git a/src/content/docs/en/reference/container-reference.mdx b/src/content/docs/en/reference/container-reference.mdx new file mode 100644 index 0000000000000..df0ff6bab2e39 --- /dev/null +++ b/src/content/docs/en/reference/container-reference.mdx @@ -0,0 +1,295 @@ +--- +title: Astro Container API (experimental) +i18nReady: false +--- +import Since from '~/components/Since.astro' + +<p><Since v="4.9.0" /></p> + +The Container API allows you to render Astro components in isolation. + +This experimental server-side API unlocks a variety of potential future uses, but is currently scoped to allow [unit testing of `.astro` component output](/en/guides/testing/#vitest-and-container-api). This API allows you to create a new container, and render an Astro component returning a string or a `Response`. + +This API is experimental and subject to breaking changes, even in [minor or patch releases](/en/upgrade-astro/#semantic-versioning). Please consult [the Astro CHANGELOG](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md) for changes as they occur. This page will always be updated with the most current information for the latest version of Astro. + +## `create()` + +Creates a new instance of the container. + +```js +import { experimental_AstroContainer } from "astro/container"; + +const container = await experimental_AstroContainer.create(); +``` + +It accepts an object with the following options: + + +```ts +export type AstroContainerOptions = { + streaming?: boolean; + renderers?: AstroRenderer[]; +}; +``` + +#### `streaming` option + +**Type:** `boolean` + +Enables rendering components using [HTML streaming](/en/guides/server-side-rendering/#html-streaming). + +#### `renderers` option + +**Type:**: `AstroRenderer[]`; + +A list of client renderers required by the component. Use this if your `.astro` component renders any [UI framework components](/en/guides/framework-components/) using an official Astro integration (e.g. React, Vue, etc.). For each framework rendered, you must provide an object stating the integration package `name`, as well as both its `client` and `server` rendering script + +The following example provides the necessary object to render an Astro component that renders a React component: + +```js +const container = await experimental_AstroContainer.create({ + renderers: [ + { + name: "@astrojs/react", + client: "@astrojs/react/client.js", + server: "@astrojs/react/server.js" + } + ] +}) +const result = await container.renderToString(ReactWrapper); +``` + +## `renderToString()` + +This function renders a specified component inside a container. It takes an Astro component as an argument and it returns a string that represents the HTML/content rendered by the Astro component. + +```js +import { experimental_AstroContainer } from "astro/container"; +import Card from "../src/components/Card.astro"; + +const container = await experimental_AstroContainer.create(); +const result = await container.renderToString(Card); +``` + +Under the hood, this function calls [`renderToResponse`](#rendertoresponse) and calls `Response.text()`. + +It also accepts an object as a second argument that can contain a [number of options](#rendering-options). + +## `renderToResponse()` + +It renders a component, and it returns a `Response` object. + +```js +import { experimental_AstroContainer } from "astro/container"; +import Card from "../src/components/Card.astro"; + +const container = await experimental_AstroContainer.create(); +const result = await container.renderToResponse(Card); +``` + +It also accepts an object as a second argument that can contain a [number of options](#rendering-options). + +### Rendering options + +Both [`renderToResponse`](#rendertoresponse) and [`renderToString`](#rendertostring) accept an object as their second argument: + +```ts +export type ContainerRenderOptions = { + slots?: Record<string, any>; + request?: Request; + params?: Record<string, string | undefined>; + locals?: App.Locals; + routeType?: "page" | "endpoint"; + +}; +``` + +These optional values can be passed to the rendering function in order to provide additional information necessary for an Astro component to properly render. + +#### `slots` + +**Type**: `Record<string, any>`; + +An option to pass content to be rendered with [`<slots>`](en/basics/astro-components/#slots). + +If your Astro component renders one default slot, pass an object with `default` as the key: + +```js name="Card.test.js" +import Card from "../src/components/Card.astro"; + +const result = await container.renderToString(Card, { + slots: { default: "Some value"} +}); +``` + +If your component renders named slots, use the slot names as the object keys: + +```astro name="Card.astro" +--- +--- +<div> + <slot name="header" /> + <slot name="footer" /> +</div> +``` + +```js name="Card.test.js" +import Card from "../src/components/Card.astro"; + +const result = await container.renderToString(Card, { + slots: { "header": "Header content", "footer": "Footer" } +}); +``` + +You can also render components in cascade: + +```astro name="Card.astro" +--- +--- +<div> + <slot name="header" /> + <slot name="footer" /> +</div> +``` + +```js name="Card.test.js" +import Card from "../src/components/Card.astro"; +import CardHeader from "../src/components/CardHeader.astro"; +import CardFooter from "../src/components/CardFooter.astro"; + +const result = await container.renderToString(Card, { + slots: { + "header": await container.renderToString(CardHeader), + "footer": await container.renderToString(CardFooter), + } +}); +``` + +#### `request` option + +**Type**: `Request` + +An option to pass a `Request` with information about the path/URL the component will render. + +Use this option when your component needs to read information like `Astro.url` or `Astro.request`. + +You can also inject possible headers or cookies. + +```js file="Card.test.js" +import Card from "../src/components/Card.astro"; + +const result = await container.renderToString(Card, { + request: new Request("https://example.com/blog", { + headers: { + "X-some-secret-header": "test-value" + } + }) +}); +``` + +#### `params` option + +**Type**: `Record<string, string | undefined>`; + +An object to pass information about the path parameter to an Astro component responsible for [generating dynamic routes](/en/guides/routing/#dynamic-routes). + +Use this option when your component needs a value for `Astro.params` in order to generate a single route dynamically. + +```astro name="Card.astro" +--- +const { locale, slug } = Astro.params; +--- +<div></div> +``` + +```js file="LocaleSlug.test.js" +import LocaleSlug from "../src/components/[locale]/[slug].astro"; + +const result = await container.renderToString(LocaleSlug, { + params: { + locale: "en", + slug: "getting-started" + } +}); +``` + +#### `locals` options + +**Type**: `App.Locals` + +An option to pass information from [`Astro.locals`](/en/reference/api-reference/#astrolocals) for rendering your component. + +Use this option to when your component needs information stored during the lifecycle of a request in order to render, such as logged in status. + +```astro name="Card.astro" +--- +const { checkAuth } = Astro.locals; +const isAuthenticated = checkAuth(); +--- +{isAuthenticated ? <span>You're in</span> : <span>You're out</span> } +``` + +```js file="Card.test.js" +import Card from "../src/components/Card.astro"; + +test("User is in", async () => { + const result = await container.renderToString(Card, { + locals: { + checkAuth() { return true } + } + }); + + // assert result contains "You're in" +}) + + +test("User is out", async () => { + const result = await container.renderToString(Card, { + locals: { + checkAuth() { return false } + } + }); + + // assert result contains "You're out" +}) +``` + +#### `routeType` option + +**Type**: `"page" | "endpoint"` + +An option available when using `renderToResponse` to specify that you are rendering an [endpoint](/en/guides/endpoints/): + +```js +container.renderToString(Endpoint, { routeType: "endpoint" }); +``` + +```js file="endpoint.test.js" +import * as Endpoint from "../src/pages/api/endpoint.js"; + +const response = await container.renderToResponse(Endpoint, { + routeType: "endpoint" +}); +const json = await response.json(); +``` + +To test your endpoint on methods such as `POST`, `PATCH`, etc., use the `request` option to call the correct function: + +```js file="endpoint.js" +export function GET() {} + +// need to test this +export function POST() {} +``` + +```js file="endpoint.test.js" ins={5-7} +import * as Endpoint from "../src/pages/api/endpoint.js"; + +const response = await container.renderToResponse(Endpoint, { + routeType: "endpoint", + request: new Request("https://example.com", { + method: "POST" // + }) +}); +const json = await response.json(); +``` diff --git a/src/i18n/en/nav.ts b/src/i18n/en/nav.ts index 04c0146d2fcb3..9d6cbf05f2624 100644 --- a/src/i18n/en/nav.ts +++ b/src/i18n/en/nav.ts @@ -178,6 +178,11 @@ export default [ slug: 'reference/dev-toolbar-app-reference', key: 'reference/dev-toolbar-app-reference', }, + { + text: 'Container API', + slug: 'reference/container-reference', + key: 'reference/container-reference', + }, { text: 'Template Directives', slug: 'reference/directives-reference', From 51f4d616512f0f1e3f6b46d8d44bd8d395500d66 Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa <my.burning@gmail.com> Date: Wed, 22 May 2024 13:16:39 +0100 Subject: [PATCH 03/10] feat: i18n domains (#8285) Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --- .../docs/en/guides/internationalization.mdx | 113 +++++++++--------- 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/src/content/docs/en/guides/internationalization.mdx b/src/content/docs/en/guides/internationalization.mdx index fdd11a03d84a0..44efcb393c370 100644 --- a/src/content/docs/en/guides/internationalization.mdx +++ b/src/content/docs/en/guides/internationalization.mdx @@ -179,6 +179,61 @@ Setting `prefixDefaultLocale: true` will also automatically set `redirectToDefau You can opt out of this behavior by [setting `redirectToDefaultLocale: false`](/en/reference/configuration-reference/#i18nroutingredirecttodefaultlocale). This allows you to have a site home page that exists outside of your configured locale folder structure. +### `domains` + +<p><Since v="4.9.0" /></p> + +This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured. + +To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, add `i18n.domains` to map any of your supported `locales` to custom URLs: + +```js title="astro.config.mjs" {3-7} ins={14-21} +import { defineConfig } from "astro/config" +export default defineConfig({ + site: "https://example.com", + output: "server", // required, with no prerendered pages + adapter: node({ + mode: 'standalone', + }), + i18n: { + defaultLocale: "en", + locales: ["es", "en", "fr", "ja"], + routing: { + prefixDefaultLocale: false + }, + domains: { + fr: "https://fr.example.com", + es: "https://example.es" + } + } +}) +``` + +All non-mapped `locales` will follow your `prefixDefaultLocales` configuration. However, even if this value is `false`, page files for your `defaultLocale` must also exist within a localized folder. For the configuration above, an `/en/` folder is required. + +With the above configuration: + +- The file `/fr/about.astro` will create the URL `https://fr.example.com/about`. +- The file `/es/about.astro` will create the URL `https://example.es/about`. +- The file `/ja/about.astro` will create the URL `https://example.com/ja/about`. +- The file `/en/about.astro` will create the URL `https://example.com/about`. + +The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. + +#### Limitations + +This feature has some restrictions: +- The `site` option is mandatory. +- The `output` option must be set to `"server"`. +- There cannot be any individual prerendered pages. +- The adapter feature [`functionPerRoute`](/en/reference/adapter-reference/#functionperroute) is not supported. + +Astro relies on the following headers in order to support the feature: +- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host). Astro will use the former, and if not present, will try the latter. +- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`URL#protocol`](https://developer.mozilla.org/en-US/docs/Web/API/URL/protocol) of the server request. + +Make sure that your server proxy/hosting platform is able to provide this information. Failing to retrieve these headers will result in a 404 (status code) page. + ### `manual` <p><Since v="4.6.0" /></p> @@ -308,63 +363,5 @@ export default defineConfig({ Astro will ensure that a page is built in `src/pages/fr` for every page that exists in `src/pages/es/`. If the page does not already exist, then a page with a redirect to the corresponding `es` route will be created. -## `domains` (experimental) - -<p><Since v="4.3.0" /></p> - -This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured. - -To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, set the `experimental.i18nDomains` flag to `true` and add `i18n.domains` to map any of your supported `locales` to custom URLs: - -```js title="astro.config.mjs" {3-7} ins={14-21} -import { defineConfig } from "astro/config" -export default defineConfig({ - site: "https://example.com", - output: "server", // required, with no prerendered pages - adapter: node({ - mode: 'standalone', - }), - i18n: { - defaultLocale: "en", - locales: ["es", "en", "fr", "ja"], - routing: { - prefixDefaultLocale: false - }, - domains: { - fr: "https://fr.example.com", - es: "https://example.es" - } - }, - experimental: { - i18nDomains: true - } -}) -``` - -All non-mapped `locales` will follow your `prefixDefaultLocales` configuration. However, even if this value is `false`, page files for your `defaultLocale` must also exist within a localized folder. For the configuration above, an `/en/` folder is required. - -With the above configuration: - -- The file `/fr/about.astro` will create the URL `https://fr.example.com/about`. -- The file `/es/about.astro` will create the URL `https://example.es/about`. -- The file `/ja/about.astro` will create the URL `https://example.com/ja/about`. -- The file `/en/about.astro` will create the URL `https://example.com/about`. - -The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. - -#### Limitations - -This feature has some restrictions: -- The `site` option is mandatory. -- The `output` option must be set to `"server"`. -- There cannot be any individual prerendered pages. -- The adapter feature [`functionPerRoute`](/en/reference/adapter-reference/#functionperroute) is not supported. - -Astro relies on the following headers in order to support the feature: -- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host). Astro will use the former, and if not present, will try the latter. -- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`URL#protocol`](https://developer.mozilla.org/en-US/docs/Web/API/URL/protocol) of the server request. - -Make sure that your server proxy/hosting platform is able to provide this information. Failing to retrieve these headers will result in a 404 (status code) page. - [`site`]: /en/reference/configuration-reference/#site [`i18n.locales`]: /en/reference/configuration-reference/#i18nlocales From 132d2115051f6a6c09229ebf1b94376fc60b07ad Mon Sep 17 00:00:00 2001 From: "Houston (Bot)" <108291165+astrobot-houston@users.noreply.github.com> Date: Wed, 22 May 2024 06:37:13 -0700 Subject: [PATCH 04/10] ci: update reference docs (#8368) Co-authored-by: sarah11918 <sarah11918@users.noreply.github.com> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> --- .../en/reference/configuration-reference.mdx | 108 +++++++----------- 1 file changed, 39 insertions(+), 69 deletions(-) diff --git a/src/content/docs/en/reference/configuration-reference.mdx b/src/content/docs/en/reference/configuration-reference.mdx index 1fc536998d317..c970ef5dfae02 100644 --- a/src/content/docs/en/reference/configuration-reference.mdx +++ b/src/content/docs/en/reference/configuration-reference.mdx @@ -354,6 +354,45 @@ Using `'class'` is helpful when you want to ensure that element selectors within Using `'where'` gives you more control over specificity, but requires that you use higher-specificity selectors, layers, and other tools to control which selectors are applied. Using `'attribute'` is useful when you are manipulating the `class` attribute of elements and need to avoid conflicts between your own styling logic and Astro's application of styles. +### security + +<p> + +**Type:** `boolean`<br /> +**Default:** `{}`<br /> +<Since v="4.9.0" /> +</p> + +Enables security measures for an Astro website. + +These features only exist for pages rendered on demand (SSR) using `server` mode or pages that opt out of prerendering in `hybrid` mode. + +```js +// astro.config.mjs +export default defineConfig({ + output: "server", + security: { + checkOrigin: true + } +}) +``` + +#### security.checkOrigin + +<p> + +**Type:** `boolean`<br /> +**Default:** 'false'<br /> +<Since v="4.9.0" /> +</p> + +When enabled, performs a check that the "origin" header, automatically passed by all modern browsers, matches the URL sent by each `Request`. This is used to provide Cross-Site Request Forgery (CSRF) protection. + +The "origin" check is executed only for pages rendered on demand, and only for the requests `POST`, `PATCH`, `DELETE` and `PUT` with +one of the following `content-type` headers: `'application/x-www-form-urlencoded'`, `'multipart/form-data'`, `'text/plain'`. + +If the "origin" header doesn't match the `pathname` of the request, Astro will return a 403 status code and will not render the page. + ### vite <p> @@ -1438,75 +1477,6 @@ With `experimental.globalRoutingPriority` enabled (instead of Astro 4.0 default In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes. -### experimental.i18nDomains - -<p> - -**Type:** `boolean`<br /> -**Default:** `false`<br /> -<Since v="4.3.0" /> -</p> - -Enables domain support for the [experimental `domains` routing strategy](/en/guides/internationalization/#domains-experimental) which allows you to configure the URL pattern of one or more supported languages to use a custom domain (or sub-domain). - -When a locale is mapped to a domain, a `/[locale]/` path prefix will not be used. However, localized folders within `src/pages/` are still required, including for your configured `defaultLocale`. - -Any other locale not configured will default to a localized path-based URL according to your `prefixDefaultLocale` strategy (e.g. `https://example.com/[locale]/blog`). - -```js -//astro.config.mjs -export default defineConfig({ - site: "https://example.com", - output: "server", // required, with no prerendered pages - adapter: node({ - mode: 'standalone', - }), - i18n: { - defaultLocale: "en", - locales: ["en", "fr", "pt-br", "es"], - prefixDefaultLocale: false, - domains: { - fr: "https://fr.example.com", - es: "https://example.es", - }, - }, - experimental: { - i18nDomains: true, - }, -}); -``` - -Both page routes built and URLs returned by the `astro:i18n` helper functions [`getAbsoluteLocaleUrl()`](/en/reference/api-reference/#getabsolutelocaleurl) and [`getAbsoluteLocaleUrlList()`](/en/reference/api-reference/#getabsolutelocaleurllist) will use the options set in `i18n.domains`. - -See the [Internationalization Guide](/en/guides/internationalization/#domains-experimental) for more details, including the limitations of this experimental feature. - -### experimental.security - -<p> - -**Type:** `boolean`<br /> -**Default:** `false`<br /> -<Since v="4.6.0" /> -</p> - -Enables CSRF protection for Astro websites. - -The CSRF protection works only for pages rendered on demand (SSR) using `server` or `hybrid` mode. The pages must opt out of prerendering in `hybrid` mode. - -```js -// astro.config.mjs -export default defineConfig({ - output: "server", - experimental: { - security: { - csrfProtection: { - origin: true - } - } - } -}) -``` - ### experimental.rewriting <p> From 66548e2ecc20faad2b5c0078a83f0b80e2101dfa Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Wed, 22 May 2024 13:44:24 +0000 Subject: [PATCH 05/10] tiny fixes --- src/content/docs/en/guides/testing.mdx | 2 +- src/content/docs/en/reference/container-reference.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/en/guides/testing.mdx b/src/content/docs/en/guides/testing.mdx index b100dce6b95a1..2de98351c4cd7 100644 --- a/src/content/docs/en/guides/testing.mdx +++ b/src/content/docs/en/guides/testing.mdx @@ -48,7 +48,7 @@ See the [Astro + Vitest starter template](https://github.com/withastro/astro/tre #### Vitest and Container API -<Since v="4.9.0" /> +<p><Since v="4.9.0" /></p> You can natively test Astro components using the [container API](/en/reference/container-reference/). First, setup [`vitest` as explained above](#vitest), then create a `.test.js` file to test your component: diff --git a/src/content/docs/en/reference/container-reference.mdx b/src/content/docs/en/reference/container-reference.mdx index df0ff6bab2e39..4c5afe26cbbdc 100644 --- a/src/content/docs/en/reference/container-reference.mdx +++ b/src/content/docs/en/reference/container-reference.mdx @@ -8,7 +8,7 @@ import Since from '~/components/Since.astro' The Container API allows you to render Astro components in isolation. -This experimental server-side API unlocks a variety of potential future uses, but is currently scoped to allow [unit testing of `.astro` component output](/en/guides/testing/#vitest-and-container-api). This API allows you to create a new container, and render an Astro component returning a string or a `Response`. +This experimental server-side API unlocks a variety of potential future uses, but is currently scoped to allow [testing of `.astro` component output](/en/guides/testing/#vitest-and-container-api). This API allows you to create a new container, and render an Astro component returning a string or a `Response`. This API is experimental and subject to breaking changes, even in [minor or patch releases](/en/upgrade-astro/#semantic-versioning). Please consult [the Astro CHANGELOG](https://github.com/withastro/astro/blob/main/packages/astro/CHANGELOG.md) for changes as they occur. This page will always be updated with the most current information for the latest version of Astro. From 250ffca6a68e3b61d9d1bbad6b126bde6c2e5ed8 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Thu, 23 May 2024 07:18:06 -0300 Subject: [PATCH 06/10] move domains section --- .../docs/en/guides/internationalization.mdx | 111 +++++++++--------- 1 file changed, 55 insertions(+), 56 deletions(-) diff --git a/src/content/docs/en/guides/internationalization.mdx b/src/content/docs/en/guides/internationalization.mdx index 44efcb393c370..3d6848fd10927 100644 --- a/src/content/docs/en/guides/internationalization.mdx +++ b/src/content/docs/en/guides/internationalization.mdx @@ -178,62 +178,6 @@ Setting `prefixDefaultLocale: true` will also automatically set `redirectToDefau You can opt out of this behavior by [setting `redirectToDefaultLocale: false`](/en/reference/configuration-reference/#i18nroutingredirecttodefaultlocale). This allows you to have a site home page that exists outside of your configured locale folder structure. - -### `domains` - -<p><Since v="4.9.0" /></p> - -This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured. - -To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, add `i18n.domains` to map any of your supported `locales` to custom URLs: - -```js title="astro.config.mjs" {3-7} ins={14-21} -import { defineConfig } from "astro/config" -export default defineConfig({ - site: "https://example.com", - output: "server", // required, with no prerendered pages - adapter: node({ - mode: 'standalone', - }), - i18n: { - defaultLocale: "en", - locales: ["es", "en", "fr", "ja"], - routing: { - prefixDefaultLocale: false - }, - domains: { - fr: "https://fr.example.com", - es: "https://example.es" - } - } -}) -``` - -All non-mapped `locales` will follow your `prefixDefaultLocales` configuration. However, even if this value is `false`, page files for your `defaultLocale` must also exist within a localized folder. For the configuration above, an `/en/` folder is required. - -With the above configuration: - -- The file `/fr/about.astro` will create the URL `https://fr.example.com/about`. -- The file `/es/about.astro` will create the URL `https://example.es/about`. -- The file `/ja/about.astro` will create the URL `https://example.com/ja/about`. -- The file `/en/about.astro` will create the URL `https://example.com/about`. - -The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. - -#### Limitations - -This feature has some restrictions: -- The `site` option is mandatory. -- The `output` option must be set to `"server"`. -- There cannot be any individual prerendered pages. -- The adapter feature [`functionPerRoute`](/en/reference/adapter-reference/#functionperroute) is not supported. - -Astro relies on the following headers in order to support the feature: -- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host). Astro will use the former, and if not present, will try the latter. -- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`URL#protocol`](https://developer.mozilla.org/en-US/docs/Web/API/URL/protocol) of the server request. - -Make sure that your server proxy/hosting platform is able to provide this information. Failing to retrieve these headers will result in a 404 (status code) page. - ### `manual` <p><Since v="4.6.0" /></p> @@ -328,6 +272,61 @@ export default defineConfig({ When using functions from the [`astro:i18n` virtual module](/en/reference/api-reference/#internationalization-astroi18n) to compute valid URL paths based on your configuration (e.g. `getRelativeLocaleUrl()`), [use the `path` as the value for `locale`](/en/reference/api-reference/#getlocalebypath). +## `domains` + +<p><Since v="4.9.0" /></p> + +This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured. + +To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, add `i18n.domains` to map any of your supported `locales` to custom URLs: + +```js title="astro.config.mjs" {3-7} ins={14-21} +import { defineConfig } from "astro/config" +export default defineConfig({ + site: "https://example.com", + output: "server", // required, with no prerendered pages + adapter: node({ + mode: 'standalone', + }), + i18n: { + defaultLocale: "en", + locales: ["es", "en", "fr", "ja"], + routing: { + prefixDefaultLocale: false + }, + domains: { + fr: "https://fr.example.com", + es: "https://example.es" + } + } +}) +``` + +All non-mapped `locales` will follow your `prefixDefaultLocales` configuration. However, even if this value is `false`, page files for your `defaultLocale` must also exist within a localized folder. For the configuration above, an `/en/` folder is required. + +With the above configuration: + +- The file `/fr/about.astro` will create the URL `https://fr.example.com/about`. +- The file `/es/about.astro` will create the URL `https://example.es/about`. +- The file `/ja/about.astro` will create the URL `https://example.com/ja/about`. +- The file `/en/about.astro` will create the URL `https://example.com/about`. + +The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. + +#### Limitations + +This feature has some restrictions: +- The `site` option is mandatory. +- The `output` option must be set to `"server"`. +- There cannot be any individual prerendered pages. +- The adapter feature [`functionPerRoute`](/en/reference/adapter-reference/#functionperroute) is not supported. + +Astro relies on the following headers in order to support the feature: +- [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Host). Astro will use the former, and if not present, will try the latter. +- [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) and [`URL#protocol`](https://developer.mozilla.org/en-US/docs/Web/API/URL/protocol) of the server request. + +Make sure that your server proxy/hosting platform is able to provide this information. Failing to retrieve these headers will result in a 404 (status code) page. + ## Browser language detection Astro’s i18n routing allows you to access two properties for browser language detection in pages rendered on demand: `Astro.preferredLocale` and `Astro.preferredLocaleList`. All pages, including static prerendered pages, have access to `Astro.currentLocale`. From 7dbdc5161cb18d96f988259e97e3d588aab1aa3b Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Thu, 23 May 2024 07:21:47 -0300 Subject: [PATCH 07/10] update heading levels for better TOC --- .../docs/en/reference/container-reference.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/docs/en/reference/container-reference.mdx b/src/content/docs/en/reference/container-reference.mdx index 4c5afe26cbbdc..b675ed2e28496 100644 --- a/src/content/docs/en/reference/container-reference.mdx +++ b/src/content/docs/en/reference/container-reference.mdx @@ -89,7 +89,7 @@ const result = await container.renderToResponse(Card); It also accepts an object as a second argument that can contain a [number of options](#rendering-options). -### Rendering options +## Rendering options Both [`renderToResponse`](#rendertoresponse) and [`renderToString`](#rendertostring) accept an object as their second argument: @@ -106,7 +106,7 @@ export type ContainerRenderOptions = { These optional values can be passed to the rendering function in order to provide additional information necessary for an Astro component to properly render. -#### `slots` +### `slots` **Type**: `Record<string, any>`; @@ -165,7 +165,7 @@ const result = await container.renderToString(Card, { }); ``` -#### `request` option +### `request` option **Type**: `Request` @@ -187,7 +187,7 @@ const result = await container.renderToString(Card, { }); ``` -#### `params` option +### `params` option **Type**: `Record<string, string | undefined>`; @@ -213,7 +213,7 @@ const result = await container.renderToString(LocaleSlug, { }); ``` -#### `locals` options +### `locals` options **Type**: `App.Locals` @@ -254,7 +254,7 @@ test("User is out", async () => { }) ``` -#### `routeType` option +### `routeType` option **Type**: `"page" | "endpoint"` From 77ea4ef374407ecb6e9254d5417b410f69df0292 Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Thu, 23 May 2024 07:30:40 -0300 Subject: [PATCH 08/10] Better spot for `domains` --- .../docs/en/guides/internationalization.mdx | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/content/docs/en/guides/internationalization.mdx b/src/content/docs/en/guides/internationalization.mdx index 3d6848fd10927..6e23f6d831663 100644 --- a/src/content/docs/en/guides/internationalization.mdx +++ b/src/content/docs/en/guides/internationalization.mdx @@ -245,33 +245,6 @@ export const onRequest = sequence( ) ``` -## Custom locale paths - -In addition to defining your site's supported `locales` as strings (e.g. "en", "pt-br"), Astro also allows you to map an arbitrary number of [browser-recognized language `codes`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax) to a custom URL `path`. While locales can be strings of any format as long as they correspond to your project folder structure, `codes` must follow the browser's accepted syntax. - -Pass an object to the `locales` array with a `path` key to define a custom URL prefix, and `codes` to indicate the languages mapped to this URL. In this case, your `/[locale]/` folder name must match exactly the value of the `path` and your URLs will be generated using the `path` value. - -This is useful if you support multiple variations of a language (e.g. `"fr"`, `"fr-BR"`, and `"fr-CA"`) and you want to have all these variations mapped under the same URL `/fr/`, or even customize it entirely (e.g. `/french/`): - -```js title="astro.config.mjs" del={5} ins={6-9} -import { defineConfig } from "astro/config" -export default defineConfig({ - i18n: { - defaultLocale: "en", - locales: ["es", "en", "fr"], - locales: ["es", "en", { - path: "french", // no slashes included - codes: ["fr", "fr-BR", "fr-CA"] - }], - routing: { - prefixDefaultLocale: true - } - } -}) -``` - -When using functions from the [`astro:i18n` virtual module](/en/reference/api-reference/#internationalization-astroi18n) to compute valid URL paths based on your configuration (e.g. `getRelativeLocaleUrl()`), [use the `path` as the value for `locale`](/en/reference/api-reference/#getlocalebypath). - ## `domains` <p><Since v="4.9.0" /></p> @@ -313,6 +286,33 @@ With the above configuration: The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. +## Custom locale paths + +In addition to defining your site's supported `locales` as strings (e.g. "en", "pt-br"), Astro also allows you to map an arbitrary number of [browser-recognized language `codes`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax) to a custom URL `path`. While locales can be strings of any format as long as they correspond to your project folder structure, `codes` must follow the browser's accepted syntax. + +Pass an object to the `locales` array with a `path` key to define a custom URL prefix, and `codes` to indicate the languages mapped to this URL. In this case, your `/[locale]/` folder name must match exactly the value of the `path` and your URLs will be generated using the `path` value. + +This is useful if you support multiple variations of a language (e.g. `"fr"`, `"fr-BR"`, and `"fr-CA"`) and you want to have all these variations mapped under the same URL `/fr/`, or even customize it entirely (e.g. `/french/`): + +```js title="astro.config.mjs" del={5} ins={6-9} +import { defineConfig } from "astro/config" +export default defineConfig({ + i18n: { + defaultLocale: "en", + locales: ["es", "en", "fr"], + locales: ["es", "en", { + path: "french", // no slashes included + codes: ["fr", "fr-BR", "fr-CA"] + }], + routing: { + prefixDefaultLocale: true + } + } +}) +``` + +When using functions from the [`astro:i18n` virtual module](/en/reference/api-reference/#internationalization-astroi18n) to compute valid URL paths based on your configuration (e.g. `getRelativeLocaleUrl()`), [use the `path` as the value for `locale`](/en/reference/api-reference/#getlocalebypath). + #### Limitations This feature has some restrictions: From 70548e0286e51adce40d795bf1e7a460be9b193a Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Thu, 23 May 2024 07:45:20 -0300 Subject: [PATCH 09/10] make `fallback` consistent with other options --- .../docs/en/guides/internationalization.mdx | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/content/docs/en/guides/internationalization.mdx b/src/content/docs/en/guides/internationalization.mdx index 6e23f6d831663..b543e2f53d673 100644 --- a/src/content/docs/en/guides/internationalization.mdx +++ b/src/content/docs/en/guides/internationalization.mdx @@ -251,7 +251,7 @@ export const onRequest = sequence( This routing option allows you to customize your domains on a per-language basis for `server` rendered projects using the [`@astrojs/node`](/en/guides/integrations-guide/node/) or [`@astrojs/vercel`](/en/guides/integrations-guide/vercel/) adapter with a `site` configured. -To enable this in your project, [configure i18n routing](#configure-i18n-routing) with your preferences if you have not already done so. Then, add `i18n.domains` to map any of your supported `locales` to custom URLs: +Add `i18n.domains` to map any of your supported `locales` to custom URLs: ```js title="astro.config.mjs" {3-7} ins={14-21} import { defineConfig } from "astro/config" @@ -286,6 +286,27 @@ With the above configuration: The above URLs will also be returned by the `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` functions. +## `fallback` + +Astro's i18n routing allows you to configure a **fallback routing strategy**. When a page in one language doesn't exist (e.g. a page that is not yet translated), instead of displaying a 404 page, you can redirect a user from one locale to another on a per-language basis. This is useful when you do not yet have a page for every route, but you want to still provide some content to your visitors. + +For example, the configuration below sets `es` as the fallback locale for any missing `fr` routes. This means that a user visiting `example.com/fr/my-page/` will be redirected to and shown the content for `example.com/es/my-page/` instead of being taken to a 404 page when `src/pages/fr/my-page.astro` does not exist. + +```js title="astro.config.mjs" ins={6-8} +import { defineConfig } from "astro/config" +export default defineConfig({ + i18n: { + defaultLocale: "en", + locales: ["es", "en", "fr"], + fallback: { + fr: "es" + } + } +}) +``` + +Astro will ensure that a page is built in `src/pages/fr` for every page that exists in `src/pages/es/`. If the page does not already exist, then a page with a redirect to the corresponding `es` route will be created. + ## Custom locale paths In addition to defining your site's supported `locales` as strings (e.g. "en", "pt-br"), Astro also allows you to map an arbitrary number of [browser-recognized language `codes`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax) to a custom URL `path`. While locales can be strings of any format as long as they correspond to your project folder structure, `codes` must follow the browser's accepted syntax. @@ -341,26 +362,5 @@ These combine the browser's `Accept-Language` header, and your `locales` (string In order to successfully match your visitors' preferences, provide your `codes` using the same pattern [used by the browser](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language#syntax). -## Fallback - -Astro's i18n routing allows you to configure a **fallback routing strategy**. When a page in one language doesn't exist (e.g. a page that is not yet translated), instead of displaying a 404 page, you can redirect a user from one locale to another on a per-language basis. This is useful when you do not yet have a page for every route, but you want to still provide some content to your visitors. - -For example, the configuration below sets `es` as the fallback locale for any missing `fr` routes. This means that a user visiting `example.com/fr/my-page/` will be redirected to and shown the content for `example.com/es/my-page/` instead of being taken to a 404 page when `src/pages/fr/my-page.astro` does not exist. - -```js title="astro.config.mjs" ins={6-8} -import { defineConfig } from "astro/config" -export default defineConfig({ - i18n: { - defaultLocale: "en", - locales: ["es", "en", "fr"], - fallback: { - fr: "es" - } - } -}) -``` - -Astro will ensure that a page is built in `src/pages/fr` for every page that exists in `src/pages/es/`. If the page does not already exist, then a page with a redirect to the corresponding `es` route will be created. - [`site`]: /en/reference/configuration-reference/#site [`i18n.locales`]: /en/reference/configuration-reference/#i18nlocales From ef063093f887dfd54580783511e5a8799f53704b Mon Sep 17 00:00:00 2001 From: Sarah Rainsberger <sarah@rainsberger.ca> Date: Thu, 23 May 2024 07:45:56 -0300 Subject: [PATCH 10/10] give title to a code block Co-authored-by: Chris Swithinbank <swithinbank@gmail.com> --- src/content/docs/en/guides/testing.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/en/guides/testing.mdx b/src/content/docs/en/guides/testing.mdx index 2de98351c4cd7..86801e6a956d3 100644 --- a/src/content/docs/en/guides/testing.mdx +++ b/src/content/docs/en/guides/testing.mdx @@ -52,7 +52,7 @@ See the [Astro + Vitest starter template](https://github.com/withastro/astro/tre You can natively test Astro components using the [container API](/en/reference/container-reference/). First, setup [`vitest` as explained above](#vitest), then create a `.test.js` file to test your component: -```js +```js title="example.test.js" import { experimental_AstroContainer as AstroContainer } from 'astro/container'; import { expect, test } from 'vitest'; import Card from '../src/components/Card.astro';