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

Localized pathnames don't work with Dynamic params #643

Closed
Benlasc opened this issue Nov 17, 2023 · 9 comments
Closed

Localized pathnames don't work with Dynamic params #643

Benlasc opened this issue Nov 17, 2023 · 9 comments
Labels
bug Something isn't working unconfirmed Needs triage.

Comments

@Benlasc
Copy link

Benlasc commented Nov 17, 2023

Description

Hello, I used the github code: next-intl/examples/example-app-router to show you my problem (see the codesandbox link below).

In the src/config.ts file I defined a url with a dynamic parameter id :

/customer/[id]': {
en: '/customer/[id]',
de: '/customer-de/[id]'.

When the user is on the /en/customer/100 url and chooses the 'de' locale, I'd like the url to become /de/customer-de/100.

The problem is that I have an error on the line "router.replace(pathname, {locale: nextLocale})" in the "LocaleSwitcherSelect.tsx" file:

Error: Insufficient params provided for localized pathname.
Template: /customer-de/[id]
Params: undefined

Is this a bug that needs to be fixed or an error on my part?

Thank you.

Mandatory reproduction URL (CodeSandbox or GitHub repository)

https://codesandbox.io/p/sandbox/next-intl-bug-template-app-forked-yy3xtl?file=%2Fsrc%2Fconfig.ts%3A12%2C24

Reproduction description

Steps to reproduce:

  1. Go to the url /en/customer/100
  2. Change the locale from English to German
  3. See the error message:

Error: Insufficient params provided for localized pathname.
Template: /customer-de/[id]
Params: undefined

Expected behaviour

When the user is on the /en/customer/100 url and chooses the 'de' locale, I'd like the url to become /de/customer-de/100.

@Benlasc Benlasc added bug Something isn't working unconfirmed Needs triage. labels Nov 17, 2023
@amannn
Copy link
Owner

amannn commented Nov 17, 2023

Hey, you probably want to check "How can I change the locale for the current page?" in the useRouter docs.

Hope this helps!

@Benlasc
Copy link
Author

Benlasc commented Nov 17, 2023

OK, thank you, I've finally replaced it:

startTransition(() => {
  router.replace(pathname, {locale: nextLocale});
});

with this:

startTransition(() => {
  router.replace({pathname: '/customer/[id]', params: {id: '100'}}, {location: nextLocale});
});

Thanks for the help

@amannn
Copy link
Owner

amannn commented Nov 17, 2023

Looks good! 🙌

@amannn amannn closed this as completed Nov 17, 2023
@axelpezzo
Copy link

Hello guys, I've the same issue as you.

I've implemented a LanguageSwitcher on the Header which change the website language.

When I'm on the path /en/shop/category-x/product-y (solved by a DynamicPath pattern) and I switch from english to another language I got the error: "Insufficient params provided for localized pathname" and nothing happens on the page.

If I console log the pathname returned by usePathname hook I got the folder pattern /shop/[...slug] as excpected.

The solution proposed by @Benlasc is hardcoded for that product how can I solve this in order to handle correctly all the dynamic routes inside the Website?

@evilive3000
Copy link

evilive3000 commented Jan 2, 2024

"use client";

import { useParams } from "next/navigation";
import { usePathname, useRouter } from "@/navigation";

export default function LanguageSwitcher(props: { locales: string[] }) {
  const router = useRouter();
  const pathname = usePathname();
  const params = useParams();

  const changeLanguage = (lang: string) => {
    /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
    router.push({ pathname, params: params as any }, { locale: lang });
  };

  return (
    <div>
      {props.locales.map((lang) => (
        <button key={lang} onClick={() => changeLanguage(lang)}>
          {lang.toUpperCase()}
        </button>
      ))}
    </div>
  );
}

I encountered a similar problem. It turned out that you can get the current parameters for pathname using the useParams hook. After that, everything is simple. I hope this solution saves someone some time 😉

@Mimachh
Copy link

Mimachh commented Jan 9, 2024

    /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
    router.push({ pathname, params: params as any }, { locale: lang });

Thanks, you're a boss.

@Exp1ry
Copy link

Exp1ry commented Jan 10, 2024

How can we achieve this using a Link component?

@AlanJereb
Copy link

"use client";

import { useParams } from "next/navigation";
import { usePathname, useRouter } from "@/navigation";

export default function LanguageSwitcher(props: { locales: string[] }) {
  const router = useRouter();
  const pathname = usePathname();
  const params = useParams();

  const changeLanguage = (lang: string) => {
    /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
    router.push({ pathname, params: params as any }, { locale: lang });
  };

  return (
    <div>
      {props.locales.map((lang) => (
        <button key={lang} onClick={() => changeLanguage(lang)}>
          {lang.toUpperCase()}
        </button>
      ))}
    </div>
  );
}

I encountered a similar problem. It turned out that you can get the current parameters for pathname using the useParams hook. After that, everything is simple. I hope this solution saves someone some time 😉

For anyone encountering an error Error: Insufficient params provided for localized pathname. even when doing the above suggestion, make sure, that if you are defining [...rest] inside your pathnames, put [...rest] onto the end of definition.

🟥 Wrong:

export const pathnames = {
  // If all locales use the same pathname, a
  // single external path can be provided.
  '/': '/',
  '/blog': '/blog',
  '[...rest]': '[...rest]',
  
  // If locales use different paths, you can
  // specify each external path per locale.
  '/blog/[slug]': {
    en: '/blog/[slug]',
    it: '/blog/[slug]',
    es: '/blog/[slug]',
    fr: '/blog/[slug]',
  },
} satisfies Pathnames<typeof locales>;

🟩 Correct:

export const pathnames = {
  // If all locales use the same pathname, a
  // single external path can be provided.
  '/': '/',
  '/blog': '/blog',
  
  // If locales use different paths, you can
  // specify each external path per locale.
  '/blog/[slug]': {
    en: '/blog/[slug]',
    it: '/blog/[slug]',
    es: '/blog/[slug]',
    fr: '/blog/[slug]',
  },

  '[...rest]': '[...rest]',
} satisfies Pathnames<typeof locales>;

@patateskafa
Copy link

patateskafa commented May 21, 2024

For those who came across the same issue using next-intl Link component, I think the path param mechanism is sort of bugged (using next-intl 3.12.2), or I'm missing an obvious point. At least for localized pathnames with params, when you're visiting i.e. .../posts/{some-post-uuid} page, i.e. the locale switcher's useParams() always grab id as the param and nothing else, i.e.:

Compiles but doesn't work, throws Error: Insufficient params provided for localized pathname because useParams doesn't get postId, it has id though:

<Link
      href={{
        pathname: "/posts/[postId]",
        params: { postId: post.id },
      }}>

-----------------------

export const pathnames = {
  "/posts": {
    en: "/posts",
    tr: "/yazilar",
  },
  "/posts/[postId]": {
    en: "/posts/[postId]",
    tr: "/yazilar/[postId]",
  },
} satisfies Pathnames<typeof locales>;

Works:

<Link
      href={{
        pathname: "/posts/[id]",
        params: { id: post.id },
      }}>

-----------------------

export const pathnames = {
  "/posts": {
    en: "/posts",
    tr: "/yazilar",
  },
  "/posts/[id]": {
    en: "/posts/[id]",
    tr: "/yazilar/[id]",
  },
} satisfies Pathnames<typeof locales>;

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

8 participants