amannn / next-intl

🌐 Internationalization (i18n) for Next.js
https://next-intl-docs.vercel.app
MIT License
2.58k stars 236 forks source link

router issue when switching locale: path.startsWith is not a function #1240

Closed chaotic-justice closed 3 months ago

chaotic-justice commented 3 months ago

Description

image

image

TypeError: path.startsWith is not a function encountered when switching locale

Verifications

Mandatory reproduction URL

https://github.com/chaotic-justice/summer-bee

Reproduction description

Steps to reproduce:

  1. Open reproduction
  2. Click on git clone
  3. run yarn && yarn dev
  4. See error: …

Expected behaviour

switching to a diff locale will trigger the routing error

r0skar commented 3 months ago

I am seeing the same issue.

"next": "14.2.5",
"next-intl": "3.17.2",
meabed commented 3 months ago

I have the same issue

tgdn commented 3 months ago

Same issue

NaderTate commented 3 months ago

I do that as a workaround:

                  <button
                    onClick={() => {
                      startTransition(() => {
                        const newPath = pathname.replace(
                          lang,
                          lang === "en" ? "ar" : "en"
                        );
                        push(newPath, { scroll: false });
                      });
                    }}
                  >
                    {lang === "en" ? "AR" : "EN"}
                  </button>
tgdn commented 3 months ago

You can simply call router.replace with the same pathname and the updated locale as follows to update the locale:

startTransition(() => {
  router.replace(pathname, { locale: nextLocale });
});
danielkoller commented 3 months ago

@tgdn This also worked for me - don't know if this is the correct approach, though? Routing works fine for me with this approach. Before I had the same problem like @chaotic-justice.

tgdn commented 3 months ago

@danielkoller I'm unsure, I tried and it worked. I also had the same issue.

amannn commented 3 months ago

I've just checked the reproduction from @chaotic-justice and saw that the call to router.push is invalid.

There seems to be a confusion between createSharedPathnamesNavigation and createLocalizedPathnamesNavigation.

In case of localized pathnames, you can call router.push with an object like {pathname: '/user/[userId], params: {userId: 2}} which allows to resolve a localized template. With shared pathnames however, pathnames are the same for each locale, therefore there's no need to resolve a localized template. Due to this, router.push only accepts a string argument.

const router = useRouter();
const pathname = usePathname();

// ❌ Doesn't work
router.push({pathname}, {locale: 'de'});

// ✅ Works
router.push(pathname, {locale: 'de'});

This matches what @tgdn mentioned above.

See also How can I change the locale for the current page? in the docs (make sure you have "Shared pathnames" selected in the tabs above).

After this fix, the call in the reproduction from @chaotic-justice works for me.

Note however that there are other bugs in the reproduction that need to be resolved for the app to work for me:

  1. The [lang] segment needs to be renamed to [locale] (make sure to adjust the received props in pages and layouts)
  2. The layout needs to be moved to the [locale] folder.

You might want to review the getting started docs.

Hope this helps others who ran into this issue!

giuppidev commented 1 month ago

With shared pathnames however, pathnames are the same for each locale, therefore there's no need to resolve a localized template. Due to this, router.push only accepts a string argument.

Hi @amannn , how to push with shared pathnames passing a query param? Accepting only a string as you mention I cannot accomplish it. Thanks

amannn commented 1 month ago

@giuppidev Same as with the regular Next.js redirect:

redirect('/users?page=2');
giuppidev commented 1 month ago

@giuppidev Same as with the regular Next.js redirect:

redirect('/users?page=2');

I was using it, but got an error on email string (with the + special char). So in next I would pass an object to push instead of a string.

amannn commented 1 month ago

Oh sorry, you meant useRouter().push.

So in next I would pass an object to push instead of a string.

Next.js also only supports a string argument for href in push:

Screenshot 2024-09-20 at 15 27 31

(source)

If you encounter an error, can you share a reproduction that works with Next.js but not with next-intl?