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

Next dynamic routing is incompatible with next-i18next's Link #413

Closed
lazidoca opened this issue Jul 22, 2019 · 49 comments
Closed

Next dynamic routing is incompatible with next-i18next's Link #413

lazidoca opened this issue Jul 22, 2019 · 49 comments

Comments

@lazidoca
Copy link

Describe the bug

I tried to use dynamic routing from Next.js with next-i18next. I imported Link from NextI18Next instead of next/link and it causes the error saying:
Your 's asvalue is incompatible with thehref value. This is invalid.

What I tried:

  • Add as property to Link as well as remove it

Does any one have the same issue?

Occurs in next-i18next version

next-i18next version: 0.50.0

Steps to reproduce

I set up a minimal repository here:
https://github.com/lazidoca/dynamic-routing-next-i18next-app

Expected behaviour

You must provide a clear and concise description of what you expected to happen.

OS (please complete the following information)

  • Device: Windows 10
  • Browser: Chrome 75.0.3770.142
  • Node: v10.16.0
@lazidoca lazidoca changed the title Next dynamic routing with next-i18next not work Next dynamic routing is incompatible with next-i18next's Link Jul 22, 2019
@SkeLLLa
Copy link

SkeLLLa commented Jul 22, 2019

We've faced the same problem. The root cause I think is that it uses incorrect router on frontend side. And it fails during change method call.
It tries to match as with lang: /en/foo/bar with route template without a lang /[item]/[subitem].

So i18next should override client side change function https://github.com/zeit/next.js/blob/canary/packages/next-server/lib/router/router.ts#L243 and correct _as parameter by removing lang from it. And in this case it will pass check here https://github.com/zeit/next.js/blob/canary/packages/next-server/lib/router/router.ts#L294 and will work as expected.

@isaachinman
Copy link
Contributor

The Link component that next-i18next exports does not call change or do anything imperatively. It simply returns the default Link component from next/link, modifying the href and as props where necessary.

I believe this is related to vercel/next.js#7488.

Here's some JSX that causes the error, within a next-i18next project:

<Link href='/post/[id]' as='/post/second'>
    <a>Second Post</a>
</Link>

With localeSubpaths set to "all", and a current language of "en", we'd expect this Link to eventually lead to /en/post/second, while displaying the page located at pages/post/[id]. Instead, we get the error:

Your `<Link>`'s `as` value is incompatible with the `href` value. This is invalid.

However, this doesn't appear to be specifically related to next-i18next. If you import Link directly from next/link and change your JSX to:

<Link href='/post/[id]' as='/en/post/second'>
    <a>Second Post</a>
</Link>

You will see the exact same error.

Not sure what to say, except that we might need to drop localeSubpath support altogether, as it has always been a complicated and opinionated thing to support, and there isn't a clear way forward.

@SkeLLLa
Copy link

SkeLLLa commented Jul 23, 2019

The Link component that next-i18next exports does not call change or do anything imperatively. It simply returns the default Link component from next/link, modifying the href and as props where necessary.

Actually those "modifications" of props cause an error. As a result of such modifications we receive something like this in href: /foo/[bar]?lng=en and /en/foo/barValue in as.
After that in default change method next tries to match as value with regex constructed based on href. And it obviously fails to do that.

On the other hand next-i18next modifies such urls on backend (ssr) side with middleware: https://github.com/isaachinman/next-i18next/blob/master/src/middlewares/next-i18next-middleware.js#L63

And I don't see any reason why it's not done in the same way on client side. I think it should be possible hook next's link change method with own, check if it's i18n route and modify it as well and then call original. And even if vercel/next.js#7488 will be fixed I don't think that it will fix this issue as well, because they have slightly different causes.

@isaachinman
Copy link
Contributor

As I said, try hardcoding the values you'd expect directly into a Link from next/link. If that doesn't work, do not expect next-i18next to somehow extend the default NextJs functionality.

If you have some idea for a PR, feel free to open a draft to more clearly explain your idea.

@Ble3k
Copy link

Ble3k commented Aug 11, 2019

Can anyone suggest any workarounds here ?

@lazidoca
Copy link
Author

lazidoca commented Aug 21, 2019

Can anyone suggest any workarounds here ?

I ended up using next-routes instead of Next's dynamic routing.

@kormang
Copy link

kormang commented Aug 23, 2019

I've simply made my own simple Link that wrapps next's Link, and does not take language off, but prepends '[lang]/' to the href, and I also have [lang] folder in root of my project. I also had to change middleware so that it does not cut language part off URL.

  const ni18nmiddleware = nextI18NextMiddleware(nextI18next)
  if (nextI18next.config.localeSubpaths && nextI18next.config.localeSubpaths !== 'none') {
    ni18nmiddleware.pop() // remove last element which is middleware that takes off [lang] part of URL
  }
  server.use(ni18nmiddleware)

@mattboon
Copy link

mattboon commented Aug 23, 2019

We worked around this issue by using this library:
https://github.com/yahoohung/next-i18n-routes

Comprised of a few pieces:

1) server/routes.js to serve dynamic i18n routes

import nextI18nRoutes from 'next-i18n-routes'

// @ts-ignore
const routes = nextI18nRoutes({
  locales: ['en', 'de'],
  defaultLocale: 'en',
})

routes.add('videos/slug', '/videos/:slug')

export const Link = routes.Link
export const Router = routes.Router

export default routes

2) Server setup as-per the ReadMe

3) <DynamicLink> component for linking to dynamic routes

import { LinkProps } from 'next-i18n-routes'
import React, { FC } from 'react'
import { Link } from '../server/routes'
import { i18n } from '../i18n' // your next-i18next instance

export interface DynamicLinkProps extends LinkProps {
  passHref?: boolean
}

const DynamicLink: FC<DynamicLinkProps> = ({ children, params, passHref = true, ...props }) => {
  // @ts-ignore
  const linkParams = i18n.language === i18n.options.defaultLanguage
    ? params
    : { lang: i18n.language, ...params }

  return (
    <Link params={linkParams} passHref={passHref} {...props}>
      {children}
    </Link>
  )
}

export default DynamicLink

Usage:

<DynamicLink route="videos/slug" params={{ slug: 'example-video' }}>
  <a>
    Link to example video
  </a>
<DynamicLink>

4) Folder structure

- /pages
  - /videos
    - slug.tsx

Note: do not name your page [slug].tsx as a filename with [ ] will use Next's dynamic routing instead of the custom workaround

@vimutti77
Copy link

Calling i18n.changeLanguage(foo) in dynamic page also not working properly. The language is changed but the url is not.

@isaachinman
Copy link
Contributor

@vimutti77 That might be a separate issue. Any client side calls to changeLanguage should trigger this callback. If you think you're experiencing a bug there, please do open a separate issue.

@RafaPolit
Copy link

This is more or less a deal breaker as it is right now. This makes all the usefulness of this approach to i18n really limited to static routes. Is there a recommended workaround that does not involve duplicating the entire site by hand for each language? Thanks.

@isaachinman
Copy link
Contributor

@RafaPolit This problem occurs when users:

  1. Need localeSubpaths
  2. Need dynamic routing

Essentially, the two are mutually exclusive due to a limitation on the NextJs side of things. Please do feel free to have a look at the implementation here and see if you can come up with a creative fix.

In general, if people want to see this implemented, the most helpful thing to do is make some noise over in the NextJs repo.

@oswaldoacauan
Copy link

This is a huge deal breaker and should be stated in the first lines of the readme. 🤦‍♂

@isaachinman
Copy link
Contributor

@oswaldoacauan Feel free to relay your frustrations to the NextJs team. Not sure if it's a "deal breaker", as there are no other prebuilt options that I'm aware of. There are workarounds posted above.

@oswaldoacauan
Copy link

oswaldoacauan commented Sep 19, 2019

@isaachinman for sure I will. Anyway I think a warning or pin this issue is not a bad call.
When I see an active project like this I would expect it to support and integrate with all latest features of the main lib. 🤷‍♂

Anyway good work. I will try to find a workaround and update here if I succeed :)

@LotharVM
Copy link

This might be a bit hacky, but it's a pretty simple workaround and works for me.

Have your folder structure like this:

- pages
  - news
    - [id].js
    - page.js

Write your code in Page.js and in [id].js, the following:

import Page from './page';
export default Page;

Then, use i18n's Link component just like this:

<Link href={`/news/page?id=${post.slug}`} as={`/news/${post.slug}`}>
    <a>{post.title}</a>
</Link>

Client-side navigation & SSR 🎉

@DenisDov
Copy link

DenisDov commented Jan 3, 2020

First i retrieve current locale:

Blog.getInitialProps = async function({ req }) {
  const locale = req ? req.language : i18n.language;
  return {
    namespacesRequired: ["blog"],
    locale
  };
};

After that i'm passing the current locale to link and its working for me:

const Blog = ({ data, t, locale }) => (
  <section>
    <div className="container">
      <H1>{t("title")}</H1>
      <HTMLTable bordered condensed striped interactive>
        <thead>
          <tr>
            <th>#</th>
          </tr>
        </thead>
        <tbody>
          {data.map(i => (
            <Link href={`/${locale}/post/[id]`} as={`/${locale}/post/${i.id}`} key={i.id}>
              <tr>
                <td>{i.id}</td>
              </tr>
            </Link>
          ))}
        </tbody>
      </HTMLTable>
    </div>
  </section>
);

All working fine in dev mode, but when i try to deploy to NOW its crashing with error:

502: BAD_GATEWAY
Code: NO_STATUS_CODE_FROM_FUNCTION
ID: hel1:87q67-1578078587415-c6135aa41bf7

Detal log:

2020-01-03T19:12:07.807Z	undefined	ERROR	Uncaught Exception	{"errorType":"Error","errorMessage":"ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'","code":"ENOENT","errno":-2,"syscall":"scandir","path":"/var/task/public/static/locales/en","stack":["Error: ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'","    at Object.readdirSync (fs.js:790:3)","    at getAllNamespaces (/var/task/.next/serverless/pages/index.js:8754:19)","    at createConfig (/var/task/.next/serverless/pages/index.js:8759:27)","    at new NextI18Next (/var/task/.next/serverless/pages/index.js:9808:48)","    at Object.k7Sn (/var/task/.next/serverless/pages/index.js:8818:18)","    at __webpack_require__ (/var/task/.next/serverless/pages/index.js:23:31)","    at Object.1TCz (/var/task/.next/serverless/pages/index.js:552:12)","    at __webpack_require__ (/var/task/.next/serverless/pages/index.js:23:31)","    at Module.Hqw1 (/var/task/.next/serverless/pages/index.js:4330:12)","    at __webpack_require__ (/var/task/.next/serverless/pages/index.js:23:31)"]}
Duration: 765.86 ms  Billed Duration: 800 ms  Memory Size: 1024 MB  Max Memory Used: 45 MB	
Unknown application error occurred
Error

@vimutti77
Copy link

vercel/next.js/pull/9837

@isaachinman
Copy link
Contributor

Thanks @vimutti77. Can anyone confirm if the issue is resolved with Next v9.2.1?

@eduludi
Copy link

eduludi commented Jan 28, 2020

@isaachinman I'm having the same issue in v9.2.1

@eduludi
Copy link

eduludi commented Jan 28, 2020

Trying with @LotharVM solution I get it working, but with a page reload.

@vimutti77
Copy link

vimutti77 commented Jan 28, 2020

I can confirm that it is working now in next v9.2.1. @eduludi you need to supply query params to your href.

e.g.

<Link href="/[id]?id=foo" as="/foo">
  <button type="button">{t("to-second-page")}</button>
</Link>

or

<Link href={{ pathname: "/[id]", query: { id: "foo" } }} as="/foo">
  <button type="button">{t("to-second-page")}</button>
</Link>

@eduludi
Copy link

eduludi commented Jan 28, 2020

Thanks @vimutti77! It works like a charm!

@GainorB
Copy link

GainorB commented Jun 11, 2020

I've tried the solutions that @vimutti77 and @mattboon suggested, but unfortunately when I link to dynamic routes, I still get a page refresh. This only happens on dynamic routes /news/[slug]. All my other links work as intended without a full page refresh.

@michaelmota
Copy link

I've tried the solutions that @vimutti77 and @mattboon suggested, but unfortunately when I link to dynamic routes, I still get a page refresh. This only happens on dynamic routes /news/[slug]. All my other links work as intended without a full page refresh.

For dynamic routes using the Link component just do:

<Link href="/news/[slug]?slug=slug_of_route" as="/news/slug_of_route"><a>Lorem ipsum dolor</a></Link>

With that it will avoid the page refresh and it will also avoid showing errors on consoles that can't pre-load the website.

@GainorB
Copy link

GainorB commented Jun 12, 2020

I've tried the solutions that @vimutti77 and @mattboon suggested, but unfortunately when I link to dynamic routes, I still get a page refresh. This only happens on dynamic routes /news/[slug]. All my other links work as intended without a full page refresh.

For dynamic routes using the Link component just do:

<Link href="/news/[slug]?slug=slug_of_route" as="/news/slug_of_route"><a>Lorem ipsum dolor</a></Link>

With that it will avoid the page refresh and it will also avoid showing errors on consoles that can't pre-load the website.

@michaelmota Are you using Link from next/link or from next-i18next? Currently, I am using the Link from next-i18next and it's not working.

I even modified my custom server like this, as per the docs:

    server.get('/news/:slug', (req, res) => {
      const {query, params} = req;

      return app.render(req, res, '/news/[slug]', {...query, slug: params.slug});
    });

@michaelmota
Copy link

michaelmota commented Jun 12, 2020

I even modified my custom server like this, as per the docs:

    server.get('/news/:slug', (req, res) => {
      const {query, params} = req;

      return app.render(req, res, '/news/[slug]', {...query, slug: params.slug});
    });

@GainorB There's no need to add the route on the custom express server since Next handles that for you. But try this:

I customized the express server adding the next-i18next middlewares like so:

// Imports
const nextI18NextMiddleware = require('next-i18next/middleware').default
const nextI18next = require('next-i18next').default

After this is done on the server create a new i18n.js on your root directory with something like this:

import NextI18Next from 'next-i18next'

// Reference the i18n config and customize as needed
const NextI18NextInstance = new NextI18Next({
    defaultLanguage: 'es',
    otherLanguages: ['en', 'fr'],
    browserLanguageDetection: false,
    serverLanguageDetection: false,
    strictMode: false,
    localeSubpaths: {
        en: 'en',
        fr: 'fr',
    },
})

/* Optionally, export class methods as named exports */
export const { appWithTranslation, withTranslation, Router, Link, i18n } = NextI18NextInstance

And then just import the Link component from here and use as you normally would, or as mentioned before. Like import { Link } from '../../i18n'

@GainorB
Copy link

GainorB commented Jun 12, 2020

@michaelmota Thanks for your responses. This is exactly what I am doing, as you suggested.

server.ts

import nextI18NextMiddleware from 'next-i18next/middleware';
import nextI18next from '../../src/lib/i18n';

...

server.use(nextI18NextMiddleware(nextI18next));
...
server.get('*', (req: Request, res: Response) => handle(req, res));
...

i18n.ts

import isNode from 'detect-node';
import {NextComponentType, NextPageContext} from 'next';
import NextI18Next, {InitConfig} from 'next-i18next';
import {useTranslation as originalUseTranslation} from 'react-i18next';
import {DEFAULT_LANGUAGE, LOCALE_SUBPATHS} from '../../utils';

const config: InitConfig = {
  ns: [
    Namespaces._error,
    Namespaces.common,
    Namespaces.home,
    Namespaces.assets,
    Namespaces.newsroom,
    Namespaces.article,
  ],
  defaultNS: Namespaces.common,
  load: 'currentOnly',
  lowerCaseLng: true,
  cleanCode: true,
  defaultLanguage: DEFAULT_LANGUAGE,
  preload: [DEFAULT_LANGUAGE],
  fallbackLng: DEFAULT_LANGUAGE,
  otherLanguages: ['ar', 'zh_cn', 'zh_tw', 'th', 'ja', 'ko'],
  whitelist: ['en', 'ar', 'zh_cn', 'zh_tw', 'th', 'ja', 'ko'],
  localePath: isServer ? 'public/locales' : 'locales',
  localeSubpaths: LOCALE_SUBPATHS,
  interpolation: {
    escapeValue: false,
  },
  browserLanguageDetection: true,
  serverLanguageDetection: true,
  debug: process.env.NODE_ENV === 'development' ? true : false,
  strictMode: process.env.NODE_ENV === 'development' ? true : false,
};

const NextI18NextInstance = new NextI18Next(config);

export const useTranslation = originalUseTranslation;
export const {appWithTranslation, withTranslation, Link, i18n, Trans} = NextI18NextInstance;

export const includeDefaultNamespaces = (namespaces: string[]) => [
  Namespaces.common,
  Namespaces._error,
  ...namespaces,
];

export type I18nPage<P = {}> = NextComponentType<
  NextPageContext,
  {namespacesRequired: string[]},
  P & {namespacesRequired?: string[]}
>;

export default NextI18NextInstance;

Link.ts

import {withTranslation, Namespaces, Link} from '../../lib/i18n';

    <Link passHref href={href} as={as} replace={replace} scroll={scroll} {...rest}>
      <StyledAnchor>{children}</StyledAnchor>
    </Link>

Get's passed these values, as an example"

    const href = `/news/[slug]?slug=${featuredArticle.slug}`;
    const as = `/news/${featuredArticle.slug}`;

@michaelmota
Copy link

That's weird. I remember I used to have that problem but it worked with what I mentioned before but it seems like you've done it right. The only thing left to see is check the version you have on next, i18next and next-i18next and if it's not updated try updating it to the latest version and test it again to see if it's working correctly.

Here's a part of my custom express server.

...
const nextI18NextMiddleware = require('next-i18next/middleware').default
const nextI18next = require('next-i18next').default
...

const NextI18NextInstance = new nextI18next({
    defaultLanguage: 'es',
    otherLanguages: ['en', 'fr'],
    browserLanguageDetection: false,
    serverLanguageDetection: false,
    strictMode: false,
    localeSubpaths: {
        en: 'en',
        fr: 'fr',
    },
})

;(async () => {
    ...
    await NextI18NextInstance.initPromise
    server.use(nextI18NextMiddleware(NextI18NextInstance))
    ...
    server.get('*', (req, res) => handle(req, res))
    ...
})()

@pixelass
Copy link

pixelass commented Jul 24, 2020

Here is our "not so hacky" approach:

const pathJoin = (...parts: string[]) => parts.join("/").replace(/\/+/g, "/");

const LocaleLink = ({ as, href, ...props }) => {
	const {
		i18n: {
			language,
			options: { localeSubpaths },
		},
	} = useTranslation();
	const lang = Object.values(localeSubpaths).includes(language) ? language : "";
	const withAbsolute = href.substr(0, 1) === "/" ? "/" : "";
	return <Link {...props} href={pathJoin(withAbsolute, lang, href)} as={as} />;
};

const MyComponent = () => {
	return (
		<LocaleLink href="/just-some-dir/[slug]" as={`/just-some-dir/${slug}`} passHref>
				<a>It just works</a>
		</LocaleLink>
	);
}

This will

  • append the subPath if defined
  • handle absolute and relative paths (probably not really needed and could be removed)

No need to add extra directories or other hacks.

Maybe this can be added to this lib? @isaachinman what do you think? (I can open a PR for it)

@isaachinman
Copy link
Contributor

@pixelass If you can extend the existing Link component to support dynamic routing, of course a PR would be accepted! Thanks.

@pixelass
Copy link

pixelass commented Jul 24, 2020

@isaachinman I built this HOC on top of the Link provided by this lib, so yes I can either extend the existing Link component or add a new dedicated component instead.

Personally I think extending the the existing Link component would make sense since it's backwards compatible.

@isaachinman
Copy link
Contributor

@pixelass We would want to extend the existing component, and we would need unit tests and most likely e2e tests as well.

@isaachinman
Copy link
Contributor

@pixelass Since you seem to be having a look around, just be aware that we've got utils like subpath-from-lng and subpath-is-required that should handle most of the heavy lifting for you.

@pixelass
Copy link

Sadly my HOC does not work as expected. Looks like we won't be able to use this library afterall

@oswaldoacauan
Copy link

oswaldoacauan commented Jul 27, 2020

The way we fixed this is by not using the route prefix feature and actually implementing it ourselves. We have just a small middleware and all our routes look like /[language]/some-route/[dynamic]/path. Then you just use the language as a normal dynamic part from your path.

@isaachinman
Copy link
Contributor

@pixelass Can I offer any assistance? What didn't work?

@pixelass
Copy link

pixelass commented Jul 27, 2020

@isaachinman we have a rather complicated setup so while it's very nice to offer help we will have to figure this one out ourselves (I'm currently in discovery of our project-setup).

tldr;

The HOC didn't work, it was causing a server-side render instead of client-side.
I noticed this while digging into the code of next-i18next. I tried fixing this within https://github.com/isaachinman/next-i18next/blob/master/src/utils/lng-path-corrector.ts#L42 and then realized that the issue can't be fixed with my approach. Let's just say: "I was tired and overworked when I wrote all those comments".

I think right now the solution from #413 (comment) or #413 (comment) should work.

...
...
IN DETAIL

Context
Our urls are fully localized so even switching the language causes complications since the english page doesn't know the urls of the other languages and simply switching the subpath will not work.

Example

  • https://example.com/en-US/this-is-an-example/with-a-slug
  • https://example.com/de-DE/dies-ist-ein-beispiel/mit-einem-slug.
  • https://example.com/[subpath]/[dir]/[slug]. ("[dir]" is mapped but the slug is delivered from the CMS and therefore unknown)

I might look into it some other time but right now I'm not sure if we can use this library (which is not due to this library but our url-logic)

@oswaldoacauan
Copy link

oswaldoacauan commented Jul 27, 2020 via email

@marteloge
Copy link

marteloge commented Aug 21, 2020

(Repo: https://github.com/marteloge/inktemplate)

Unhandled Runtime Error
Error: The provided `as` value (/no/create/857d1caf-3405-437d-8219-e0d667910982) is incompatible with the `href` value (/create/[uuid]). Read more: https://err.sh/vercel/next.js/incompatible-href-as

I have imported Router from my i18n.js file.

Router.push(`/create/[uuid]`, `/create/${uuid}`);

I guess it is related to the same issue with Link as described in this ticket.
The router and link work perfectly for my default language without language slug.

This kinda works but it throws a 404 before properly navigating:

Router.push(`/create/${uuid}`);
<Link href={`/create/${uuid}`}><a>Click here</a></Link>

How it should work according to NextJS (?):

Router.push(`/create/[uuid]`, `/create/${uuid}`);
<Link href="/create/[uuid]" as={`/create/${uuid}`}><a>Click here</a></Link>

Am I doing something wrong?
And is there a workaround for Router and Link to properly support dynamic routes using language slug?

@marteloge
Copy link

marteloge commented Aug 21, 2020

(Repo: https://github.com/marteloge/inktemplate)

Unhandled Runtime Error
Error: The provided `as` value (/no/create/857d1caf-3405-437d-8219-e0d667910982) is incompatible with the `href` value (/create/[uuid]). Read more: https://err.sh/vercel/next.js/incompatible-href-as

I have imported Router from my i18n.js file.

Router.push(`/create/[uuid]`, `/create/${uuid}`);

I guess it is related to the same issue with Link as described in this ticket.
The router and link work perfectly for my default language without language slug.

This kinda works but it throws a 404 before properly navigating:

Router.push(`/create/${uuid}`);
<Link href={`/create/${uuid}`}><a>Click here</a></Link>

How it should work according to NextJS (?):

Router.push(`/create/[uuid]`, `/create/${uuid}`);
<Link href="/create/[uuid]" as={`/create/${uuid}`}><a>Click here</a></Link>

Am I doing something wrong?
And is there a workaround for Router and Link to properly support dynamic routes using language slug?

Seems like this worked:

Router.push(`/create/[uuid]?uuid=${uuid}`, `/create/${uuid}`);
<Link href={`/create/[uuid]?uuid=${uuid}`} as={`/create/${uuid}`}>
    <a>Click here</a>
</Link>

Should I update the README to say something about dynamic routes?
Is this an issue with Next or is there a solution for it? I am quite new to Next so I don't see a solution quite yet.

@isaachinman
Copy link
Contributor

@marteloge You can see how we wrap the Link component here. What you've arrived at looks pretty typical for NextJs routing, although the team has made some changes recently to make things a bit easier.

@GainorB
Copy link

GainorB commented Aug 23, 2020

@michaelmota Thanks for your responses. This is exactly what I am doing, as you suggested.

server.ts

import nextI18NextMiddleware from 'next-i18next/middleware';
import nextI18next from '../../src/lib/i18n';

...

server.use(nextI18NextMiddleware(nextI18next));
...
server.get('*', (req: Request, res: Response) => handle(req, res));
...

i18n.ts

import isNode from 'detect-node';
import {NextComponentType, NextPageContext} from 'next';
import NextI18Next, {InitConfig} from 'next-i18next';
import {useTranslation as originalUseTranslation} from 'react-i18next';
import {DEFAULT_LANGUAGE, LOCALE_SUBPATHS} from '../../utils';

const config: InitConfig = {
  ns: [
    Namespaces._error,
    Namespaces.common,
    Namespaces.home,
    Namespaces.assets,
    Namespaces.newsroom,
    Namespaces.article,
  ],
  defaultNS: Namespaces.common,
  load: 'currentOnly',
  lowerCaseLng: true,
  cleanCode: true,
  defaultLanguage: DEFAULT_LANGUAGE,
  preload: [DEFAULT_LANGUAGE],
  fallbackLng: DEFAULT_LANGUAGE,
  otherLanguages: ['ar', 'zh_cn', 'zh_tw', 'th', 'ja', 'ko'],
  whitelist: ['en', 'ar', 'zh_cn', 'zh_tw', 'th', 'ja', 'ko'],
  localePath: isServer ? 'public/locales' : 'locales',
  localeSubpaths: LOCALE_SUBPATHS,
  interpolation: {
    escapeValue: false,
  },
  browserLanguageDetection: true,
  serverLanguageDetection: true,
  debug: process.env.NODE_ENV === 'development' ? true : false,
  strictMode: process.env.NODE_ENV === 'development' ? true : false,
};

const NextI18NextInstance = new NextI18Next(config);

export const useTranslation = originalUseTranslation;
export const {appWithTranslation, withTranslation, Link, i18n, Trans} = NextI18NextInstance;

export const includeDefaultNamespaces = (namespaces: string[]) => [
  Namespaces.common,
  Namespaces._error,
  ...namespaces,
];

export type I18nPage<P = {}> = NextComponentType<
  NextPageContext,
  {namespacesRequired: string[]},
  P & {namespacesRequired?: string[]}
>;

export default NextI18NextInstance;

Link.ts

import {withTranslation, Namespaces, Link} from '../../lib/i18n';

    <Link passHref href={href} as={as} replace={replace} scroll={scroll} {...rest}>
      <StyledAnchor>{children}</StyledAnchor>
    </Link>

Get's passed these values, as an example"

    const href = `/news/[slug]?slug=${featuredArticle.slug}`;
    const as = `/news/${featuredArticle.slug}`;

I just upgraded to:

"next": "^9.5.0",
"next-i18next": "^6.0.2",

And refactored my next-18next implementation from removing the additions to the custom server to use rewrites in next.config.js, and all of my links start working without the hard reloading!!

@GainorB
Copy link

GainorB commented Sep 2, 2020

Anyone using rewrites in next.config.js running into page reloads in production?

@codesignist
Copy link

Anyone using rewrites in next.config.js running into page reloads in production?

I've just used now and it works perfect.

@codesignist
Copy link

It works fine on production mode also.
It seems this problem solved with the latest updates.

@isaachinman
Copy link
Contributor

Hi there, I have just released next-i18next@8.0.0, which uses the internationalised routing built into NextJs v10+. This new version of next-i18next is quite different, thus making this PR no longer relevant. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests