Skip to content

Commit

Permalink
feat: Sync improvements from RSC branch to main (#238)
Browse files Browse the repository at this point in the history
Syncs various improvements from #149 to the main branch.

**Features**
- Add domain-based routing for middleware
- Add `localePrefix` option for middleware
- Add `localeDetection: false` flag for middleware
- Set alternate links in middleware (and add opt-out via
`alternateLinks: false`)
- `NextIntlClientProvider` now accepts `now` as an ISO 8601 date string
additionally

**Bugfixes**
- Handle locale subtags correctly when negotiating a locale in the
middleware (e.g. `de-DE` → `de` when only `de` is configured)

**Deprecations**
- Deprecate `import {createIntlMiddleware} from 'next-intl/server'` in
favor of `import createMiddleware from 'next-intl/middleware'`
- Deprecate `import {NextIntlClientProvider} from 'next-intl/client'` in
favour of `import {NextIntlClientProvider} from 'next-intl'`. As part of
this, add a matcher (see the updated docs).

**Docs**
- Add docs for new features
- Middleware should only be applied for localized pages

**Internal changes**
- Clean up examples
- Use latest metadata API from Next.js
- Upgrade Next.js
- Add sitemap for website
- Add docs for new features

Closes #237
  • Loading branch information
amannn authored Apr 12, 2023
1 parent 7b20a18 commit 1d12ba2
Show file tree
Hide file tree
Showing 63 changed files with 1,910 additions and 567 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
registry-url: 'https://registry.npmjs.org'
- uses: bahmutov/npm-install@v1
# Seems like after squash & merge the author is unknown to lerna
- run: git config --global user.email "jan@amann.me" && git config --global user.name "Jan Amann"
- run: git config --global user.email "jan@amann.work" && git config --global user.name "Jan Amann"
- run: yarn run publish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion packages/example-advanced/global.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// Declaring this interface provides type safety for message keys
// Use type safe message keys with `next-intl`
type Messages = typeof import('./messages/en.json');
declare interface IntlMessages extends Messages {}
8 changes: 4 additions & 4 deletions packages/example-advanced/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@
"dependencies": {
"accept-language-parser": "1.5.0",
"lodash": "^4.17.21",
"next": "^13.0.0",
"next": "^13.3.0",
"next-intl": "^2.12.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.6.3"
"react-dom": "^18.2.0"
},
"devDependencies": {
"@testing-library/react": "^13.0.0",
Expand All @@ -27,6 +26,7 @@
"eslint": "^8.12.0",
"eslint-config-molindo": "^6.0.0",
"eslint-config-next": "^13.0.0",
"jest": "^27.4.5"
"jest": "^27.4.5",
"typescript": "^4.6.3"
}
}
2 changes: 1 addition & 1 deletion packages/example-advanced/src/pages/api/hello.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default async function handler(
namespace: 'Index'
});

// Creates the same object that is returned by `useIntl`.
// Creates the same object that is returned by `useFormatter`.
const format = createFormatter({locale});

res.status(200).json({
Expand Down
3 changes: 3 additions & 0 deletions packages/example-next-13/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Use type safe message keys with `next-intl`
type Messages = typeof import('./messages/en.json');
declare interface IntlMessages extends Messages {}
6 changes: 3 additions & 3 deletions packages/example-next-13/messages/de.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"Head": {
"title": "next-intl Beispiel"
},
"Index": {
"title": "Start",
"description": "Das ist die Startseite."
},
"LocaleLayout": {
"title": "next-intl Beispiel"
},
"LocaleSwitcher": {
"switchLocale": "Zu {locale, select, de {Deutsch} en {Englisch} other {Unbekannt}} wechseln"
}
Expand Down
6 changes: 3 additions & 3 deletions packages/example-next-13/messages/en.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"Head": {
"title": "next-intl example"
},
"Index": {
"title": "Home",
"description": "This is the home page."
},
"LocaleLayout": {
"title": "next-intl example"
},
"LocaleSwitcher": {
"switchLocale": "Switch to {locale, select, de {German} en {English} other {Unknown}}"
}
Expand Down
11 changes: 4 additions & 7 deletions packages/example-next-13/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,10 @@
"start": "next start"
},
"dependencies": {
"accept-language-parser": "1.5.0",
"date-fns": "^2.16.1",
"lodash": "^4.17.21",
"next": "^13.0.5",
"next": "^13.3.0",
"next-intl": "^2.12.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.6.3"
"react-dom": "^18.2.0"
},
"devDependencies": {
"@playwright/test": "1.28.1",
Expand All @@ -26,6 +22,7 @@
"@types/react": "^18.0.23",
"eslint": "^8.12.0",
"eslint-config-molindo": "^6.0.0",
"eslint-config-next": "^13.0.0"
"eslint-config-next": "^13.0.0",
"typescript": "^4.6.3"
}
}
3 changes: 2 additions & 1 deletion packages/example-next-13/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const config: PlaywrightTestConfig = {
],
webServer: {
command: 'yarn start',
port: 3000
port: 3000,
reuseExistingServer: true
}
};

Expand Down
29 changes: 0 additions & 29 deletions packages/example-next-13/src/app/[locale]/head.tsx

This file was deleted.

15 changes: 14 additions & 1 deletion packages/example-next-13/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {NextIntlClientProvider} from 'next-intl/client';
import {createTranslator, NextIntlClientProvider} from 'next-intl';
import {notFound} from 'next/navigation';
import {ReactNode} from 'react';

Expand All @@ -7,6 +7,19 @@ type Props = {
params: {locale: string};
};

export async function generateMetadata({params: {locale}}: Props) {
const messages = (await import(`../../../messages/${locale}.json`)).default;

// You can use the core (non-React) APIs when you have to use next-intl
// outside of components. Potentially this will be simplified in the future
// (see https://next-intl-docs.vercel.app/docs/next-13/server-components).
const t = createTranslator({locale, messages});

return {
title: t('LocaleLayout.title')
};
}

export default async function LocaleLayout({
children,
params: {locale}
Expand Down
9 changes: 7 additions & 2 deletions packages/example-next-13/src/middleware.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {createIntlMiddleware} from 'next-intl/server';
import createMiddleware from 'next-intl/middleware';

export default createIntlMiddleware({
export default createMiddleware({
locales: ['en', 'de'],
defaultLocale: 'en'
});

export const config = {
// Skip all paths that should not be internationalized
matcher: ['/((?!api|_next|.*\\..*).*)']
};
4 changes: 2 additions & 2 deletions packages/example-next-13/tests/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import {test as it, expect} from '@playwright/test';

it('handles i18n routing', async ({page}) => {
await page.goto('/');
await expect(page).toHaveURL(/\/en/);
await expect(page).toHaveURL('/');

// A cookie remembers the last locale
await page.goto('/de');
await page.goto('/');
await expect(page).toHaveURL(/\/de/);
await expect(page).toHaveURL('/de');

await page.goto('/unknown');
});
Expand Down
3 changes: 3 additions & 0 deletions packages/example/global.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Use type safe message keys with `next-intl`
type Messages = typeof import('./messages/en.json');
declare interface IntlMessages extends Messages {}
9 changes: 4 additions & 5 deletions packages/example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@
},
"dependencies": {
"date-fns": "^2.16.1",
"lodash": "^4.17.21",
"next": "^13.0.0",
"next": "^13.3.0",
"next-intl": "^2.12.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.6.3"
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/lodash": "^4.14.176",
"@types/node": "^17.0.23",
"@types/react": "^18.0.23",
"eslint": "^8.12.0",
"eslint-config-molindo": "^6.0.0",
"eslint-config-next": "^13.0.0"
"eslint-config-next": "^13.0.0",
"typescript": "^4.6.3"
}
}
11 changes: 10 additions & 1 deletion packages/next-intl/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
require('eslint-config-molindo/setupPlugins');

module.exports = {
extends: ['molindo/typescript', 'molindo/react']
extends: ['molindo/typescript', 'molindo/react', 'molindo/jest'],
plugins: ['deprecation'],
overrides: [
{
files: ['test/**/*.tsx'],
rules: {
'deprecation/deprecation': 'error'
}
}
]
};
1 change: 1 addition & 0 deletions packages/next-intl/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dist
1 change: 0 additions & 1 deletion packages/next-intl/client.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/next-intl/middleware.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {default} from './dist/src/middleware';
19 changes: 11 additions & 8 deletions packages/next-intl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
"name": "next-intl",
"version": "2.12.0",
"sideEffects": false,
"author": "Jan Amann <jan@amann.me>",
"author": "Jan Amann <jan@amann.work>",
"description": "A minimal, but complete solution for internationalization in Next.js apps.",
"license": "MIT",
"homepage": "https://next-intl-docs.vercel.app/",
"homepage": "https://next-intl-docs.vercel.app",
"repository": {
"type": "git",
"url": "https://github.com/amannn/next-intl"
Expand All @@ -28,15 +28,15 @@
"default": "./dist/index.js"
},
"./server": "./dist/src/server/index.js",
"./client": "./dist/src/client/index.js"
"./client": "./dist/src/client/index.js",
"./middleware": "./dist/src/middleware/index.js"
},
"files": [
"dist",
"src",
"server.js",
"server.d.ts",
"client.js",
"client.d.ts"
"client.d.ts",
"middleware.d.ts"
],
"keywords": [
"react",
Expand All @@ -55,7 +55,8 @@
"testEnvironment": "jsdom"
},
"dependencies": {
"accept-language-parser": "^1.5.0",
"@formatjs/intl-localematcher": "0.2.32",
"negotiator": "0.6.3",
"use-intl": "^2.12.0"
},
"peerDependencies": {
Expand All @@ -64,11 +65,13 @@
},
"devDependencies": {
"@testing-library/react": "^13.0.0",
"@types/negotiator": "0.6.1",
"@types/react": "^18.0.23",
"dts-cli": "1.4.0",
"eslint": "8.12.0",
"eslint-config-molindo": "6.0.0",
"next": "^13.0.5",
"eslint-plugin-deprecation": "1.4.0",
"next": "13.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^4.4.4"
Expand Down
1 change: 0 additions & 1 deletion packages/next-intl/server.js

This file was deleted.

44 changes: 13 additions & 31 deletions packages/next-intl/src/client/NextIntlClientProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,18 @@
'use client';

import {useRouter} from 'next/router';
import React, {ComponentProps} from 'react';
import {IntlProvider} from 'use-intl';

type Props = Omit<ComponentProps<typeof IntlProvider>, 'locale'> & {
locale?: string;
};

export default function NextIntlProvider({locale, ...rest}: Props) {
let router;
try {
// Reading from context is practically ok to do conditionally
// eslint-disable-next-line react-hooks/rules-of-hooks
router = useRouter();
} catch (error) {
// Calling `useRouter` is not supported in the app folder
}
import NextIntlClientProvider_ from '../shared/NextIntlClientProvider';

// The router can be undefined if used in a context outside
// of Next.js (e.g. unit tests, Storybook, ...)
if (!locale && router) {
locale = router.locale;
}
let hasWarned = false;
/** @deprecated Should be imported from `next-intl`, not `next-intl/client`. */
export default function NextIntlClientProvider(
props: ComponentProps<typeof NextIntlClientProvider_>
) {
if (!hasWarned) {
hasWarned = true;
console.warn(`
Importing \`NextIntlClientProvider\` from \`next-intl/client\` is deprecated. Please update the import:
if (!locale) {
throw new Error(
process.env.NODE_ENV !== 'production'
? "Couldn't determine locale. Please pass an explicit `locale` prop the provider, or if you're using the `pages` folder, use internationalized routing (https://nextjs.org/docs/advanced-features/i18n-routing)."
: undefined
);
import {NextIntlClientProvider} from 'next-intl';
`);
}

return <IntlProvider locale={locale} {...rest} />;
return <NextIntlClientProvider_ {...props} />;
}
4 changes: 3 additions & 1 deletion packages/next-intl/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export * from 'use-intl';

export {default as NextIntlClientProvider} from './shared/NextIntlClientProvider';

// Legacy export for compatibility
export {NextIntlClientProvider as NextIntlProvider} from './client';
export {default as NextIntlProvider} from './shared/NextIntlClientProvider';
Loading

1 comment on commit 1d12ba2

@vercel
Copy link

@vercel vercel bot commented on 1d12ba2 Apr 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-intl-docs – ./

next-intl-docs-git-main-amann.vercel.app
next-intl-docs-amann.vercel.app
next-intl-docs.vercel.app

Please sign in to comment.