Skip to content

Commit

Permalink
feat: Make options for createSharedPathnamesNavigation along with `…
Browse files Browse the repository at this point in the history
…locales` argument optional (relevant when `locales` aren't known statically) (#784)

Resolves #597
  • Loading branch information
amannn committed Jan 22, 2024
1 parent fed52da commit 614053d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 13 deletions.
26 changes: 19 additions & 7 deletions docs/pages/docs/routing/navigation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ export default createMiddleware({
});
```

<details>
<summary>What if the locales aren't known at build time?</summary>

In case you're building an app where locales can be added and removed at runtime, you can omit the `locales` argument from the navigation APIs. The `locale` that can be passed to APIs like `Link` will now accept any string as a valid value.

Note however that the `locales` argument for the middleware is mandatory. You can however [create the middleware dynamically](/docs/routing/middleware#composing-other-middlewares) on a per-request basis and provide the `locales` argument e.g. after fetching this from a database.

</details>

### Strategy 2: Localized pathnames [#localized-pathnames]

When using this strategy, you have to provide distinct pathnames for every locale that your app supports. However, the localized variants will be handled by a single route internally, therefore a mapping needs to be provided that is also [consumed by the middleware](/docs/routing/middleware#localizing-pathnames).
Expand Down Expand Up @@ -521,15 +530,18 @@ export async function generateMetadata({params: {locale}}) {
// Example: This page accepts search params like `?sort=asc`.
// A canonical link informs search engines that only the
// version without search params should be indexed.
const pathname = getPathname({
locale,
href: {
pathname: '/users/[userId]',
params: {userId: '5'}
}
});
return {
alternates: {
canonical: '/' + locale + getPathname({
locale,
href: {
pathname: '/users/[userId]',
params: {userId: '5'}
}
})
canonical: '/' + locale + pathname
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions packages/next-intl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@
},
{
"path": "dist/production/navigation.react-client.js",
"limit": "2.825 KB"
"limit": "2.83 KB"
},
{
"path": "dist/production/navigation.react-server.js",
"limit": "2.935 KB"
"limit": "2.94 KB"
},
{
"path": "dist/production/server.react-client.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import useBaseRouter from './useBaseRouter';

export default function createSharedPathnamesNavigation<
Locales extends AllLocales
>(opts: {locales: Locales; localePrefix?: LocalePrefix}) {
>(opts?: {locales?: Locales; localePrefix?: LocalePrefix}) {
type LinkProps = Omit<
ComponentProps<typeof ClientLink<Locales>>,
'localePrefix'
Expand All @@ -20,7 +20,7 @@ export default function createSharedPathnamesNavigation<
return (
<ClientLink<Locales>
ref={ref}
localePrefix={opts.localePrefix}
localePrefix={opts?.localePrefix}
{...props}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import serverRedirect from './serverRedirect';

export default function createSharedPathnamesNavigation<
Locales extends AllLocales
>(opts: {locales: Locales; localePrefix?: LocalePrefix}) {
>(opts?: {locales?: Locales; localePrefix?: LocalePrefix}) {
function notSupported(hookName: string) {
return () => {
throw new Error(
Expand All @@ -19,7 +19,7 @@ export default function createSharedPathnamesNavigation<
}

function Link(props: ComponentProps<typeof ServerLink<Locales>>) {
return <ServerLink<Locales> localePrefix={opts.localePrefix} {...props} />;
return <ServerLink<Locales> localePrefix={opts?.localePrefix} {...props} />;
}

function redirect(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe.each([
locales,
localePrefix: 'always'
});

describe('Link', () => {
it('renders a prefix for the default locale', () => {
const markup = renderToString(<Link href="/about">About</Link>);
Expand Down Expand Up @@ -235,5 +236,34 @@ describe.each([
});
});
});

describe('usage without statically known locales', () => {
const {Link} = createSharedPathnamesNavigation();

describe('Link', () => {
it('uses the default locale', () => {
expect(renderToString(<Link href="/about">About</Link>)).toContain(
'href="/en/about"'
);
});

it('can use a non-default locale', () => {
expect(
renderToString(
<Link href="/about" locale="de">
About
</Link>
)
).toContain('href="/de/about"');
expect(
renderToString(
<Link href="/about" locale="en">
About
</Link>
)
).toContain('href="/en/about"');
});
});
});
}
);

2 comments on commit 614053d

@vercel
Copy link

@vercel vercel bot commented on 614053d Jan 22, 2024

Choose a reason for hiding this comment

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

@vercel
Copy link

@vercel vercel bot commented on 614053d Jan 22, 2024

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 – ./docs

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

Please sign in to comment.