Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for permanentRedirect #850

Merged
merged 5 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import useLocale from '../../react-client/useLocale';
import {LocalePrefix, ParametersExceptFirst} from '../../shared/types';
import basePermanentRedirect from '../shared/basePermanentRedirect';

export default function clientPermanentRedirect(
params: {localePrefix?: LocalePrefix; pathname: string},
...args: ParametersExceptFirst<typeof basePermanentRedirect>
) {
let locale;
try {
// eslint-disable-next-line react-hooks/rules-of-hooks -- Reading from context here is fine, since `redirect` should be called during render
locale = useLocale();
} catch (e) {
throw new Error(
process.env.NODE_ENV !== 'production'
? '`permanentRedirect()` can only be called during render. To redirect in an event handler or similar, you can use `useRouter()` instead.'
: undefined
);
}

return basePermanentRedirect({...params, locale}, ...args);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
HrefOrUrlObjectWithParams
} from '../shared/utils';
import ClientLink from './ClientLink';
import clientPermanentRedirect from './clientPermanentRedirect';
import clientRedirect from './clientRedirect';
import useBasePathname from './useBasePathname';
import useBaseRouter from './useBaseRouter';
Expand Down Expand Up @@ -89,6 +90,16 @@ export default function createLocalizedPathnamesNavigation<
return clientRedirect({...opts, pathname: resolvedHref}, ...args);
}

function permanentRedirect<Pathname extends keyof PathnamesConfig>(
href: HrefOrHrefWithParams<Pathname>,
...args: ParametersExceptFirst<typeof clientPermanentRedirect>
) {
// eslint-disable-next-line react-hooks/rules-of-hooks -- Reading from context here is fine, since `redirect` should be called during render
const locale = useTypedLocale();
const resolvedHref = getPathname({href, locale});
return clientPermanentRedirect({...opts, pathname: resolvedHref}, ...args);
}

function useRouter() {
const baseRouter = useBaseRouter();
const defaultLocale = useTypedLocale();
Expand Down Expand Up @@ -156,6 +167,7 @@ export default function createLocalizedPathnamesNavigation<
return {
Link: LinkWithRef,
redirect,
permanentRedirect,
usePathname,
useRouter,
getPathname
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ParametersExceptFirst
} from '../../shared/types';
import ClientLink from './ClientLink';
import clientPermanentRedirect from './clientPermanentRedirect';
import clientRedirect from './clientRedirect';
import useBasePathname from './useBasePathname';
import useBaseRouter from './useBaseRouter';
Expand Down Expand Up @@ -37,6 +38,13 @@ export default function createSharedPathnamesNavigation<
return clientRedirect({...opts, pathname}, ...args);
}

function permanentRedirect(
pathname: string,
...args: ParametersExceptFirst<typeof clientPermanentRedirect>
) {
return clientPermanentRedirect({...opts, pathname}, ...args);
}

function usePathname(): string {
// @ts-expect-error -- Mirror the behavior from Next.js, where `null` is returned when `usePathname` is used outside of Next, but the types indicate that a string is always returned.
return useBasePathname();
Expand All @@ -45,6 +53,7 @@ export default function createSharedPathnamesNavigation<
return {
Link: LinkWithRef,
redirect,
permanentRedirect,
usePathname,
useRouter: useBaseRouter
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
normalizeNameOrNameWithParams
} from '../shared/utils';
import ServerLink from './ServerLink';
import serverPermanentRedirect from './serverPermanentRedirect';
import serverRedirect from './serverRedirect';

export default function createLocalizedPathnamesNavigation<
Expand Down Expand Up @@ -68,6 +69,15 @@ export default function createLocalizedPathnamesNavigation<
return serverRedirect({localePrefix, pathname}, ...args);
}

function permanentRedirect<Pathname extends keyof PathnamesConfig>(
href: HrefOrHrefWithParams<Pathname>,
...args: ParametersExceptFirst<typeof serverPermanentRedirect>
) {
const locale = getRequestLocale();
const pathname = getPathname({href, locale});
return serverPermanentRedirect({localePrefix, pathname}, ...args);
}

function getPathname({
href,
locale
Expand All @@ -93,6 +103,7 @@ export default function createLocalizedPathnamesNavigation<
return {
Link,
redirect,
permanentRedirect,
getPathname,
usePathname: notSupported('usePathname'),
useRouter: notSupported('useRouter')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ParametersExceptFirst
} from '../../shared/types';
import ServerLink from './ServerLink';
import serverPermanentRedirect from './serverPermanentRedirect';
import serverRedirect from './serverRedirect';

export default function createSharedPathnamesNavigation<
Expand All @@ -29,9 +30,17 @@ export default function createSharedPathnamesNavigation<
return serverRedirect({...opts, pathname}, ...args);
}

function permanentRedirect(
pathname: string,
...args: ParametersExceptFirst<typeof serverPermanentRedirect>
) {
return serverPermanentRedirect({...opts, pathname}, ...args);
}

return {
Link,
redirect,
permanentRedirect,
usePathname: notSupported('usePathname'),
useRouter: notSupported('useRouter')
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {getRequestLocale} from '../../server/react-server/RequestLocale';
import {LocalePrefix, ParametersExceptFirst} from '../../shared/types';
import basePermanentRedirect from '../shared/basePermanentRedirect';

export default function serverPermanentRedirect(
params: {pathname: string; localePrefix?: LocalePrefix},
...args: ParametersExceptFirst<typeof basePermanentRedirect>
) {
const locale = getRequestLocale();
return basePermanentRedirect({...params, locale}, ...args);
}
22 changes: 22 additions & 0 deletions packages/next-intl/src/navigation/shared/basePermanentRedirect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {permanentRedirect as nextpermanentRedirect} from 'next/navigation';
import {
AllLocales,
LocalePrefix,
ParametersExceptFirst
} from '../../shared/types';
import {prefixPathname} from '../../shared/utils';

export default function basePermanentRedirect(
params: {
pathname: string;
locale: AllLocales[number];
localePrefix?: LocalePrefix;
},
...args: ParametersExceptFirst<typeof nextpermanentRedirect>
) {
const localizedPathname =
params.localePrefix === 'never'
? params.pathname
: prefixPathname(params.locale, params.pathname);
return nextpermanentRedirect(localizedPathname, ...args);
}
Loading
Loading