Internationalized routing with translation of pages names #18485
-
Right now it is only possible to have internationalized routes like this:
What I want to do is to translate pages name too:
Some configuration object in next.config.js like this would be really cool:
|
Beta Was this translation helpful? Give feedback.
Replies: 39 comments 94 replies
-
Yes to this! This is a somewhat hard requirement for any business website in order to provide a minimally adequate user experience (at least being able to read and share URLs that are in your native language). Having url segments in the wrong language also has a considerable impact on SEO. Your idea looks a bit like the way nuxt-i18n implements it, with each page component being responsible to declare the route segment for each language (https://i18n.nuxtjs.org/routing#in-component-options). It also goes as far as providing a way to fetch/supply the translated version for any dynamic parameter route (https://i18n.nuxtjs.org/lang-switcher/#dynamic-route-parameters). I'm currently trying to figure out a way to kinda temporairly patch it on a NextJS 10 site with rewrites or something with really little success, looking forward for properly internationalized routes to be possible or a manual way to solve it in the meantime. |
Beta Was this translation helpful? Give feedback.
-
+1 for this feature request My company (for example) requires exactly this feature to move away from i18n alternatives to use only NextJS instead. |
Beta Was this translation helpful? Give feedback.
-
+1 for this also; |
Beta Was this translation helpful? Give feedback.
-
We had to do this middleware: https://github.com/trisbee/next-i18n-routes-middleware for our sites and still looking forward for official way how to achive simillar results without custom SSR. |
Beta Was this translation helpful? Give feedback.
-
+1 for this feature request |
Beta Was this translation helpful? Give feedback.
-
I believe this is now possible by using rewrites with // next.config.js
module.exports = {
async rewrites() {
return {
beforeFiles: [
{
source: '/fr/about',
destination: '/fr/sur',
locale: false
},
{
source: '/de/about',
destination: '/de/uber',
locale: false
},
],
}
},
} You can find different examples here: https://nextjs.org/docs/api-reference/next.config.js/rewrites |
Beta Was this translation helpful? Give feedback.
-
I'm also using rewrites for solution on production. https://nextjs.org/docs/api-reference/next.config.js/rewrites |
Beta Was this translation helpful? Give feedback.
-
Any updates on this? I am currently trying to solve this issue for my client too and rewrites seems like a suboptimal solution. |
Beta Was this translation helpful? Give feedback.
-
+1 for this. Migrating our existing page to NextJS and this is a major blocking issue for us currently... |
Beta Was this translation helpful? Give feedback.
-
Also... we rlly want to migrate one big multilingual website built in WP multisite, to next, but we can't make the url translation. We tried to use simply the built-in folder routing system to make the translations. Something like this: pages/index.tsx (home english) But this ends to be pointless if we can't make a dynamic lang attribute on _document.tsx. At least we could modify the header content-language using the new _middleware.ts file on next12. Please devs give us some light in this problem. i18n without the possibility to translate urls seems not too useful. |
Beta Was this translation helpful? Give feedback.
-
This is of major importance for my team as well Essentially the same content should be available on different languages on:
Ideally we would have a folder structure like so: Basically what i am looking for is a way of doing this without having to have a |
Beta Was this translation helpful? Give feedback.
-
This is the way how to solve your problem:
Create a file route.js
Use the next/link in your code as below:
|
Beta Was this translation helpful? Give feedback.
-
Crazy that this feature hasn't really had much traction considering its one of the biggest downsides to next for me and my clients. Its hard to recommend next for internationally target projects. Has anyone got client-side transitions working with the next.config.js rewrites api? I can get server-side transitions working but not client-side, and I seem to get bundling errors in dev (hot reload) mode, these errors don't happen in production mode. Also I was wondering if anyone know if it were possible to use the new nextjs 12 middleware api to do this? Would it be better? |
Beta Was this translation helpful? Give feedback.
-
For your use case, you can adopt this solution #18419 (reply in thread) and add your own slug correction / redirection logic to the _middleware. For example, when a user visits /about, we know that a redirection is required. From there, you decide which locale we should send the user to, and then in the cms, you do a look up for the right translated slug and redirect the visitor to the correct URL. /about /fr/sur /de/uber |
Beta Was this translation helpful? Give feedback.
-
The rewrite solution doesn't work for me. |
Beta Was this translation helpful? Give feedback.
-
Tim Neutkens provided an update on Twitter:
|
Beta Was this translation helpful? Give feedback.
-
We have published new docs on i18n inside the |
Beta Was this translation helpful? Give feedback.
-
So the app dir really fixed the issue with translated slugs? Or are there any caveats? |
Beta Was this translation helpful? Give feedback.
-
@leerob Hello Can you explain a little further about cost implications in sites with medium/high multilingual traffic? Is this a good strategy to business scale? Each multilingual user visit will cause a manual redirect (server/edge-function usage)? Dunno... this seems like a little forced solution.... Why I have to force a redirect for a lot of content I know in advance that should exists statically. I always considered redirections to very especific usecases for bad/wrong/removed/old urls to new ones. Sincerely, seems like a general solution that takes off responsabilities of the framework and leaves most of the logic work to the developers... not to mention cost concerns. My team was expecting a more DX friendly approach, but seems that i18n (as a whole) is not a priority topic to the core-team, and maybe it could be justified from a commercial point of view. Please... just wanna hear your thoughts on this Many Thanks |
Beta Was this translation helpful? Give feedback.
This comment was marked as disruptive content.
This comment was marked as disruptive content.
-
Thank you @leerob for a clear and direct answer :) |
Beta Was this translation helpful? Give feedback.
-
Hello there, I finally updated my old library called next-roots to support new app folder. It basically works as a generator for translated routes => takes all your routes and generate translated one based on your needs. No dynamic Also it comes with typed getHref util for creating links. Feel free to check it. Any feedback is welcome 🙂 |
Beta Was this translation helpful? Give feedback.
-
I can't update to the app directory for my project at the moment, (if you could you should!), so I found a way to do this within the middleware within a pages app. Putting it here so it might help someone. In my export default async function middleware(request: NextRequest) {
// Get this locale from somewhere, depending on how you structured your translation
if (locale) {
// Here I check if the path is translatable, to prevent the user accessing the root language urls AND the translated urls
if (pathIncludesTranslationalPart(request.nextUrl.pathname, locale)) {
request.nextUrl.pathname = `/404`;
return NextResponse.rewrite(url);
}
request.nextUrl.pathname = translatePathnameToPagesPath(request.nextUrl.pathname, locale);
}
return NextResponse.rewrite(url);
} And the functions look like this: const PAGES_PATHS_TRANSLATIONS = {
de: {
kontakt: 'contact',
suchen: 'zoeken',
},
pl: {
kontakt: 'contact',
szukac: 'zoeken',
},
};
export function pathIncludesTranslationalPart(pathName: string, locale = 'nl') {
const translationsForLocale = PAGES_PATHS_TRANSLATIONS[locale];
if (!translationsForLocale) {
return false;
}
return pathName.split('/').some((urlPart) => Object.values(translationsForLocale).includes(urlPart));
}
export function translatePathnameToPagesPath(pathName: string, locale = 'nl') {
const translationsForLocale = PAGES_PATHS_TRANSLATIONS[locale];
if (!translationsForLocale) {
return pathName;
}
return pathName
.split('/')
.map((urlPart) => translationsForLocale[urlPart] || urlPart)
.join('/');
}
// And this fn is used the other way around, to translate the pages path to the url path. This is what I use in href's of the app.
export function translatePagesPathToPathname(pathName: string, locale = 'nl') {
const translationsForLocale = PAGES_PATHS_TRANSLATIONS[locale];
if (!translationsForLocale) {
return pathName;
}
return pathName
.split('/')
.map((urlPart) => {
const foundTranslationForUrlPart = Object.entries(translationsForLocale).find(
([, orginale]) => urlPart === orginale
);
return foundTranslationForUrlPart && foundTranslationForUrlPart.length > 0
? foundTranslationForUrlPart[0]
: urlPart;
})
.join('/');
} |
Beta Was this translation helpful? Give feedback.
-
In this repository you can check out, how this can be done with app router. |
Beta Was this translation helpful? Give feedback.
-
Kinda dumb solution but it works, just import the pages in localised folders and reexport them like this:
|
Beta Was this translation helpful? Give feedback.
-
Hi ppl. After some time working with the new app router, this is my current solution to this issue preserving all static goodies and avoiding the middleware complexity or extra libs. For example, a site with home page in english as default language, but also spanish and portuguese: First I create a HomePage.tsx component, smth like this: import getPageDataByLang from '@/utils/getPageDataByLang'
import getTranslationByLang from '@/utils/getTranslationByLang'
import type { PageProps } from '@/types/PageProps'
import type { FC, ReactNode } from 'react'
const HomePage: FC<HomePageProps> = async ({ lang, children }) => {
const { title } = await getPageDataByLang(lang, 'home')
const { currentLanguage } = getTranslationByLang(lang)
return (
<div>
<h1>{title}</h1>
<p>{`${currentLanguage}: ${lang}`}</p>
</div>
)
}
type HomePageProps = {
lang: PageProps['lang'] // en | es | pt
children: ReactNode
}
export default HomePage
export type { HomePageProps } Second I organize the app folder like below:
Third I export components like this on each page (example in the 'app/(en)/page.tsx' file): import HomePage from '@/components/HomePage'
const ENHomePage = () => <HomePage lang='en' />
export default ENHomePage (Notice that all components above are RSC) The layout.tsx file follows the same approach, a The benefits that I found this way, is that now I have full control of each page in each language in a more intuitive way. And also I really don't care of automatic redirection, I left that job for the bots/crawlers. Btw, creating a language switcher is also a piace of cake. Of course, there must be a better way (specially for DX), but for now this is working nice to me. Hope it helps someone. |
Beta Was this translation helpful? Give feedback.
-
Hi everyone, I avoided the middleware solution because you can still visit the other link. I came up with this solution using rewrite and redirects. Not sure what the drawbacks would be.
|
Beta Was this translation helpful? Give feedback.
-
Just use Paraglide from Inlang: https://inlang.com/m/osslbuzt/paraglide-next-i18n/localized-routing/prefix-strategy |
Beta Was this translation helpful? Give feedback.
We have published new docs on i18n inside the
app
directory, which should enable this use case to be solved inside Middleware: https://beta.nextjs.org/docs/guides/internationalization