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

Difference in <Link/> path serverside vs clientside #808

Closed
jbreemhaar opened this issue Jan 23, 2024 · 4 comments
Closed

Difference in <Link/> path serverside vs clientside #808

jbreemhaar opened this issue Jan 23, 2024 · 4 comments
Labels
bug Something isn't working unconfirmed Needs triage.

Comments

@jbreemhaar
Copy link

jbreemhaar commented Jan 23, 2024

Description

Hi!

First off, let me say thanks for this library. My current projects now needs localized pathnames which this lib offers, so thanks!

Unfortunately I'm encountering an issue with the next-intl <Link/> component rendering the localePrefix serverside although as-needed is set as LocalePrefix. Clientside renders the correct path.
E.g. serverside renders /nl/over vs serverside /over.

This seems to be fully reproducible. Running the example-app-router with localePrefix as-needed will result in the same problem.
Any ideas?

Although kind of works for the end-user because it gets fixed by hydration and browsers with JS disabled will ultimately be redirected, it's not that nice to have in production and probably has some effect on SEO.

Mandatory reproduction URL (CodeSandbox or GitHub repository)

https://ndrx9l-3000.csb.app/

Reproduction description

Steps to reproduce:

  1. Open reproduction
  2. Use 'show source' or disable JS to view the rendered HTML.
  3. Compare the link serverside vs clientside. It's "/nl/over" serverside, it's "/over" clientside.

Expected behaviour

Serverside should render the correct path when localePrefix = 'as-needed'.

@jbreemhaar jbreemhaar added bug Something isn't working unconfirmed Needs triage. labels Jan 23, 2024
@amannn
Copy link
Owner

amannn commented Jan 23, 2024

Thanks for the kind words! This is a duplicate of #444 and mentioned in the docs, I'll close this in favour of #444.

@amannn amannn closed this as completed Jan 23, 2024
@jbreemhaar
Copy link
Author

jbreemhaar commented Jan 23, 2024

Thanks for the kind words! This is a duplicate of #444 and mentioned in the docs, I'll close this in favour of #444.

Yeah, sorry about that. Found out this was intended behaviour after posting this issue.
Here's some more context for people coming here. https://next-intl-docs.vercel.app/blog/next-intl-3-0#switching-the-middleware-default-of-localeprefix-to-always and https://next-intl-docs.vercel.app/docs/routing/middleware#locale-prefix-as-needed.

Unfortunately, I need to have this working correctly on server-side, otherwise I'll have trouble with the SEO company we pay loads of money. I'm now using a custom component that renders the correct path server-side. Our setup is relatively simple and static so I won't expect any problems with that.

@markomitranic
Copy link

@jbreemhaar I don't know if this solves your specific problem because I never experienced it, but perhaps it helps in some way, and it sounds similar to the direction you are taking :)

I've looked at the next-intl code and realized that there is almost nothing that really and intentionally differentiates server and client. We already have a function that next-intl exposes through navigation, used for path resolution and it gives us urls as strings.

I used this function getPathname to generate URLs and give them to next/link. This is able to do SSG and SSR URL resolution and requires no client.

P.S. The getPathname function is only exported with createLocalizedPathnamesNavigation. My project doesn't actually have localized paths, but in order to get that function export, I was forced to use it and manually enter all paths as shared.

@zipme
Copy link

zipme commented Apr 4, 2024

@jbreemhaar I had the same issue and I am using this workaround for now:

import { type RedirectType, redirect as nextRedirect } from "next/navigation";
import { locales, pathnames, localePrefix, defaultLocale } from './config'
import NextLink from "next/link";

export const {
  redirect,
  getPathname: getPathname_
} = createLocalizedPathnamesNavigation({ locales, pathnames, localePrefix });

export const getPathname: typeof getPathname_ = ({ href, locale }) => {
  const pathname = getPathname_({ href, locale });
  let prefix = "";
  if (locale !== defaultLocale) {
    prefix = `/${locale}`;
  }
  return `${prefix}${pathname}`;
};

export const redirect: typeof redirect_ = (href, type) => {
  const locale = useLocale();
  const path = getPathname({ href, locale });

  nextRedirect(path, type);
};

export function Link<Pathname extends keyof typeof pathnames>(
  { href, ...rest }: ComponentProps<typeof I18nLink<Pathname>>,
  ref: ForwardedRef<ElementRef<typeof NextLink>>,
) {
  const locale = useLocale();
  // @ts-expect-error this is okay
  const localizedHref = getPathname({ href, locale });
  return <NextLink href={localizedHref} {...rest} ref={ref} />;
}

Note: This won't work correctly if you have multiple domains

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working unconfirmed Needs triage.
Projects
None yet
Development

No branches or pull requests

4 participants