diff --git a/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx b/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx index 01f8eb579..23967e5e6 100644 --- a/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx +++ b/docs/src/pages/docs/environments/actions-metadata-route-handlers.mdx @@ -109,9 +109,9 @@ See the [App Router without i18n routing example](/examples#app-router-without-i ### Open Graph images -If you're programmatically generating [Open Graph images](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/opengraph-image), you can apply internationalization by calling functions from `next-intl` in the exported function: +If you're programmatically generating [Open Graph images](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/opengraph-image), you can call functions from `next-intl` in the exported component: -```tsx filename="opengraph-image.tsx" +```tsx filename="app/[locale]/opengraph-image.tsx" import {ImageResponse} from 'next/og'; import {getTranslations} from 'next-intl/server'; @@ -121,6 +121,29 @@ export default async function OpenGraphImage({params: {locale}}) { } ``` +Next.js will create a public route based on the segment where `opengraph-image.tsx` is placed, e.g.: + +``` +http://localhost:3000/en/opengraph-image?f87b2d56cee109c7 +``` + +However, if you're using [i18n routing](/docs/routing) and you've customized the [`localePrefix`](/docs/routing#locale-prefix) setting, this route might not be accessible since Next.js doesn't know about potential rewrites of the middleware. + +If this applies to your app, you can adapt your [matcher](/docs/routing/middleware#matcher-config) to bypass requests to the `opengraph-image.tsx` file: + +```tsx filename="middleware.ts" +// ... + +export const config = { + matcher: [ + // Skip all paths that should not be internationalized + '/((?!api|_next|_vercel|.*/opengraph-image|.*\\..*).*)' + + // ... + ] +}; +``` + ### Manifest Since [the manifest file](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/manifest) needs to be placed in the root of the `app` folder (outside the `[locale]` dynamic segment), you need to provide a locale explicitly since `next-intl` can't infer it from the pathname: diff --git a/examples/example-app-router-playground/src/middleware.ts b/examples/example-app-router-playground/src/middleware.ts index 7468bf33d..7d2492f4e 100644 --- a/examples/example-app-router-playground/src/middleware.ts +++ b/examples/example-app-router-playground/src/middleware.ts @@ -6,7 +6,7 @@ export default createMiddleware(routing); export const config = { matcher: [ // Skip all paths that should not be internationalized - '/((?!_next|.*\\..*).*)', + '/((?!_next|.*/opengraph-image|.*\\..*).*)', // Necessary for base path to work '/' diff --git a/examples/example-app-router-playground/tests/main.spec.ts b/examples/example-app-router-playground/tests/main.spec.ts index fb5c746cd..14288afa0 100644 --- a/examples/example-app-router-playground/tests/main.spec.ts +++ b/examples/example-app-router-playground/tests/main.spec.ts @@ -1,5 +1,5 @@ -import {test as it, expect, BrowserContext} from '@playwright/test'; -import {getAlternateLinks, assertLocaleCookieValue} from './utils'; +import {BrowserContext, expect, test as it} from '@playwright/test'; +import {assertLocaleCookieValue, getAlternateLinks} from './utils'; const describe = it.describe; @@ -618,7 +618,10 @@ it('populates metadata', async ({page}) => { ); }); -it('supports opengraph images', async ({page, request}) => { +it('supports opengraph images for the default locale', async ({ + page, + request +}) => { await page.goto('/'); const ogImage = await page .locator('meta[property="og:image"]') @@ -630,6 +633,21 @@ it('supports opengraph images', async ({page, request}) => { expect(result.ok()).toBe(true); }); +it('supports opengraph images for a locale with a custom prefix', async ({ + page, + request +}) => { + await page.goto('/spain'); + const ogImage = await page + .locator('meta[property="og:image"]') + .getAttribute('content'); + expect(ogImage).toBeTruthy(); + const ogImageUrl = new URL(ogImage!); + expect(ogImageUrl.pathname).toBe('/es/opengraph-image'); + const result = await request.get(ogImageUrl.pathname); + expect(result.ok()).toBe(true); +}); + it('can use async APIs in async components', async ({page}) => { await page.goto('/');