Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into canary
Browse files Browse the repository at this point in the history
  • Loading branch information
amannn committed Feb 17, 2025
2 parents b44c8ef + 1f44136 commit b4de1a0
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 45 deletions.
12 changes: 10 additions & 2 deletions .github/ISSUE_TEMPLATE/02_feature_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@ labels:
body:
- type: markdown
attributes:
value: Thanks for taking the time to file a feature request! Please fill out this form completely.
value: Thanks for taking the time to improve next-intl!
- type: markdown
attributes:
value: Please keep in mind that if something doesn't work as expected, you might want to [create a bug report](https://github.com/amannn/next-intl/issues/new/choose) instead. Bug reports disguised as feature requests will be closed.
value: |
Please keep in mind:
- If you're looking for specific support with your project, you can consider [asking for community support](https://github.com/amannn/next-intl/issues/new/choose) instead.
- If something doesn't work as expected, you might want to [create a bug report](https://github.com/amannn/next-intl/issues/new/choose) instead.
- Please double check the [docs](https://next-intl.dev) to see if your feature request is already supported.
- Please also check the [existing issues](https://github.com/amannn/next-intl/issues) to see if your feature request was already discussed.
If you have a feature request that has not been discussed yet, please fill out this form completely.
- type: textarea
attributes:
label: Is your feature request related to a problem? Please describe.
Expand Down
10 changes: 8 additions & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ contact_links:
- name: View documentation
url: https://next-intl.dev
about: Check out the official docs for answers to common questions
- name: Get community support
- name: Get community support on the Next.js Discord
url: https://discord.com/invite/nextjs
about: Join the Next.js community on Discord to get real-time help and connect with other developers
- name: Get community support on Stack Overflow
url: https://stackoverflow.com/questions/ask
about: Ask questions and discuss with other community members
about: Post your technical questions on Stack Overflow where experienced developers can help
- name: Get community support on GitHub Discussions
url: https://github.com/amannn/next-intl/discussions
about: Start a discussion to share ideas and ask questions
- name: Get maintainer support
url: https://github.com/sponsors/amannn?frequency=one-time
about: Book a consulting session to get help with your specific project
39 changes: 31 additions & 8 deletions docs/src/pages/blog/next-intl-4-0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Here's what's new in `[email protected]`:
3. [**Strictly-typed ICU arguments**](#strictly-typed-icu-arguments)
4. [**GDPR compliance**](#gdpr-compliance)
5. [**Modernized build output**](#modernized-build-output)
6. [**Preparation for upcoming Next.js features**](#nextjs-future)
6. [**Improved inheritance in `NextIntlClientProvider`**](#nextintlclientprovider-inheritance)
7. [**Preparation for upcoming Next.js features**](#nextjs-future)

Please also have a look at the [other breaking changes](#other-breaking-changes) listed below before you upgrade.

Expand Down Expand Up @@ -188,6 +189,30 @@ The build output of `next-intl` has been modernized and now leverages the follow

With these changes, the bundle size of `next-intl` has been reduced by ~7% ([all details](https://github.com/amannn/next-intl/pull/1470)).

## Improved inheritance of `NextIntlClientProvider` [#nextintlclientprovider-inheritance]

Previously, [`NextIntlClientProvider`](/docs/usage/configuration#nextintlclientprovider) would conservatively inherit only a subset from `i18n/request.ts`.

To improve the getting started experience, the provider now also inherits:

- `messages` ([PR #1682](https://github.com/amannn/next-intl/pull/1682))
- `formats` ([PR #1191](https://github.com/amannn/next-intl/pull/1191))

Due to this, you can now remove these props from `NextIntlClientProvider` if you've previously passed them manually:

```diff
<NextIntlClientProvider
- messages={messages}
- formats={formats}
>
{/* ... */}
</NextIntlClientProvider>
```

With this, `NextIntlClientProvider` now inherits all of your configuration, with the minor exception of [error handling functions](/docs/usage/configuration#error-handling). Since functions are not serializable, they cannot be passed across the server/client boundary. However, [an alternative](https://github.com/amannn/next-intl/issues/1285) for this is also on the horizon.

To make it easier to work with error handling functions on the client side, `NextIntlClientProvider` can now also be used in a nested fashion and will inherit the configuration from a parent provider ([PR #1413](https://github.com/amannn/next-intl/pull/1413)).

## Preparation for upcoming Next.js features [#nextjs-future]

To ensure that the sails of `next-intl` are set for a steady course in the upcoming future, I've investigated the implications of upcoming Next.js features like [`ppr`](https://nextjs.org/docs/app/api-reference/next-config-js/ppr), [`dynamicIO`](https://nextjs.org/docs/canary/app/api-reference/config/next-config-js/dynamicIO) and [`rootParams`](https://github.com/vercel/next.js/pull/72837) for `next-intl`.
Expand All @@ -205,13 +230,11 @@ I'm particularly excited about the announcement of `rootParams`, as it seems lik
## Other breaking changes

1. Return type-safe messages from `useMessages` and `getMessages` (see [PR #1489](https://github.com/amannn/next-intl/pull/1489))
2. Inherit context in case nested `NextIntlClientProvider` instances are present (see [PR #1413](https://github.com/amannn/next-intl/pull/1413))
3. Automatically inherit formats when `NextIntlClientProvider` is rendered from a Server Component (see [PR #1191](https://github.com/amannn/next-intl/pull/1191))
4. Require locale to be returned from `getRequestConfig` (see [PR #1486](https://github.com/amannn/next-intl/pull/1486))
5. Disallow passing `null`, `undefined` or `boolean` as an ICU argument (see [PR #1561](https://github.com/amannn/next-intl/pull/1561))
6. Bump minimum required TypeScript version to 5 for projects using TypeScript (see [PR #1481](https://github.com/amannn/next-intl/pull/1481))
7. Remove deprecated APIs (see [PR #1479](https://github.com/amannn/next-intl/pull/1479))
8. Remove deprecated APIs pt. 2 (see [PR #1482](https://github.com/amannn/next-intl/pull/1482))
2. Require locale to be returned from `getRequestConfig` (see [PR #1486](https://github.com/amannn/next-intl/pull/1486))
3. Disallow passing `null`, `undefined` or `boolean` as an ICU argument (see [PR #1561](https://github.com/amannn/next-intl/pull/1561))
4. Bump minimum required TypeScript version to 5 for projects using TypeScript (see [PR #1481](https://github.com/amannn/next-intl/pull/1481))
5. Remove deprecated APIs (see [PR #1479](https://github.com/amannn/next-intl/pull/1479))
6. Remove deprecated APIs pt. 2 (see [PR #1482](https://github.com/amannn/next-intl/pull/1482))

## Upgrade now

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,18 @@ async function loginAction(data: FormData) {
const t = await getTranslations('LoginForm');
const values = Object.fromEntries(data);

const result = await loginFormSchema
.refine(async (credentials) => loginUser(credentials), {
message: t('invalidCredentials')
})
.safeParseAsync(values, {
errorMap(issue, ctx) {
const path = issue.path.join('.');

const message = {
email: t('invalidEmail')
password: t('invalidPassword')
}[path];

return {message: message || ctx.defaultError};
}
});
const result = loginFormSchema.safeParse(values, {
errorMap(issue, ctx) {
const path = issue.path.join('.');

const message = {
email: t('invalidEmail')
password: t('invalidPassword')
}[path];

return {message: message || ctx.defaultError};
}
});

// ...
}
Expand Down Expand Up @@ -173,7 +169,7 @@ If you're using a sitemap to inform search engines about all pages of your site,

Note that by default, `next-intl` returns [the `link` response header](/docs/routing#alternate-links) to instruct search engines that a page is available in multiple languages. While this sufficiently links localized pages for search engines, you may choose to provide this information in a sitemap in case you have more specific requirements.

Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap) as of version 14.2. You can use your default locale for the main URL and provide alternate URLs based on all locales that your app supports. Keep in mind that also the default locale should be included in the `alternates` object.
Next.js supports providing alternate URLs per language via the [`alternates` entry](https://nextjs.org/docs/app/api-reference/file-conventions/metadata/sitemap#generate-a-localized-sitemap). You can construct a list of entries for each pathname and locale as follows:

```tsx filename="app/sitemap.ts" {4-5,8-9}
import {MetadataRoute} from 'next';
Expand All @@ -184,20 +180,20 @@ const host = 'https://acme.com';

export default function sitemap(): MetadataRoute.Sitemap {
// Adapt this as necessary
return [getEntry('/'), getEntry('/users')];
return [...getEntries('/'), ...getEntries('/users')];
}

type Href = Parameters<typeof getPathname>[0]['href'];

function getEntry(href: Href) {
return {
url: getUrl(href, routing.defaultLocale),
function getEntries(href: Href) {
return routing.locales.map((locale) => ({
url: getUrl(href, locale),
alternates: {
languages: Object.fromEntries(
routing.locales.map((locale) => [locale, getUrl(href, locale)])
routing.locales.map((cur) => [cur, getUrl(href, cur)])
)
}
};
}));
}

function getUrl(href: Href, locale: (typeof routing.locales)[number]) {
Expand All @@ -210,15 +206,20 @@ Depending on if you're using the [`pathnames`](/docs/routing#pathnames) setting,

```tsx
// 1. A final string (when not using `pathnames`)
getEntry('/users/1');
getEntries('/users/1');

// 2. An object (when using `pathnames`)
getEntry({
getEntries({
pathname: '/users/[id]',
params: {id: '1'}
});
```

**Keep in mind**:

- Each pathname should have a separate entry for every locale that your app supports.
- Also the locale of a given pathname should be included in the `alternates` object.

([working implementation](https://github.com/amannn/next-intl/blob/main/examples/example-app-router/src/app/sitemap.ts))

### Route Handlers
Expand Down
2 changes: 1 addition & 1 deletion docs/src/pages/docs/usage/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default async function RootLayout({children}) {
messages={messages}
>
{children}
</NextIntlClientProvider>
</IntlProvider>
</body>
</html>
);
Expand Down
12 changes: 6 additions & 6 deletions examples/example-app-router/src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,20 @@ import {host} from '@/config';
import {Locale, getPathname, routing} from '@/i18n/routing';

export default function sitemap(): MetadataRoute.Sitemap {
return [getEntry('/'), getEntry('/pathnames')];
return [...getEntries('/'), ...getEntries('/pathnames')];
}

type Href = Parameters<typeof getPathname>[0]['href'];

function getEntry(href: Href) {
return {
url: getUrl(href, routing.defaultLocale),
function getEntries(href: Href) {
return routing.locales.map((locale) => ({
url: getUrl(href, locale),
alternates: {
languages: Object.fromEntries(
routing.locales.map((locale) => [locale, getUrl(href, locale)])
routing.locales.map((cur) => [cur, getUrl(href, cur)])
)
}
};
}));
}

function getUrl(href: Href, locale: Locale) {
Expand Down
12 changes: 11 additions & 1 deletion examples/example-app-router/tests/main.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {test as it, expect} from '@playwright/test';
import {expect, test as it} from '@playwright/test';

it('handles i18n routing', async ({page}) => {
await page.goto('/');
Expand Down Expand Up @@ -111,10 +111,20 @@ it('serves a sitemap.xml', async ({page}) => {
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
</url>
<url>
<loc>http://localhost:3000/de</loc>
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en" />
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de" />
</url>
<url>
<loc>http://localhost:3000/en/pathnames</loc>
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
</url>
<url>
<loc>http://localhost:3000/de/pfadnamen</loc>
<xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/pathnames" />
<xhtml:link rel="alternate" hreflang="de" href="http://localhost:3000/de/pfadnamen" />
</url>
</urlset>
`
);
Expand Down
Binary file modified media/assets.sketch
Binary file not shown.

0 comments on commit b4de1a0

Please sign in to comment.