-
Notifications
You must be signed in to change notification settings - Fork 27k
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
[Example needed] i18n with Next.js 13 and app
directory
#41980
Comments
Hi @jimmyjamieson - it's noted in the beta docs here that they're not planning i18n support in Have you tried something like this? And you could probably use middleware to enable/disable specific locales. |
@aej11a Yeah, I've tried that, but that just gives a 404. I would be of benefit of allowing sub-folders under a catch-all to make internationalization easier. Will have to wait for the v13 docs to see what they suggest regarding middleware. update: It also seems middleware isn't being loaded |
Middleware only seems to work for routes under |
Middleware seems to execute correctly if you keep the pages directory. My setup has all my pages in the There's an open issue for middleware not working when the |
@johnkahn yeah, adding my 404.tsx into the pages directory has middleware working now and can access everything in the request. |
@jimmyjamieson How did you manage to solve the issue? Everytime i'm getting redirected to default locale and can't do nothing with the middleware. |
actually added |
@guttenbergovitz I would maybe report that as a bug. |
@siinghd You can see in my public repo above what I currently have. |
how to solve this issue ? |
Well... The issue is I am not 100% convinced it is a bug not the default behaviour I do not understand yet. 🤔 |
@guttenbergovitz in my repo above it seems to work. My middleware isn't exactly feature complete and messy, but the redirect is working. Links need the locale to work - or possibly wrap next/link. But you can manually add /en/sub and see it gets the correct page |
I tried this and it works on my end. I also didn't configure the {
"i18n": {
"locales": ["en-US", "fr-CA"],
"defaultLocale": ["en-US"]
}
} Then at the root of the type I18nConfig = {
i18n: {
locales: string[];
defaultLocale: string;
};
};
export default async function Layout({
children,
params,
}: PageProps) {
const locale = params.locale as string;
const locales = (i18nConfig as unknown as I18nConfig).i18n.locales.map(
(locale) => locale.toLowerCase()
);
if (!locale || !locales.includes(locale)) {
return null;
}
return (
<div>
<div>Locale: {params.locale}</div>
<div>{children}</div>
</div>
);
} Of course, this is very basic and raw (I was just testing options). I would probably expect more mature packages to be released soon to handle this instead of relying on Next.js. I myself maintain a Next.js i18n package that relies heavily on |
You might be better just doing the check and any redirects in the middleware itself. |
Hi @jimmyjamieson I was testing to implement i18n with Next13, there are some limitations, I've looked into your repo. the limitations I found still exists, please correct me:
Playground in this repo, any input is appreciated |
Yeah you're right, this is only for home. You'd have to call it for all requests and modify the redirect path to include the locale in front of the initial url. I've still to look into the other issue, but I understand what you mean. I thought about merging the locale data with the params props on page/layout and always returning it there |
I've somewhat reached an initial solution, I managed to use What I've learned on the way:
|
app
directory
Just want to follow up here and say an example for how to use i18n with the
|
app
directoryapp
directory
Hey @leerob ! Is there any chance you or the team could briefly describe what that solution will look like, even if the example isn't implemented yet? The "official word" on i18n is the biggest open question I've found holding back my team from starting incremental adoption of /app - need localization but also want to make sure we don't invest too much in the wrong approach :) Thanks for everything! Edit: really glad the new approach h will allow more flexible i18n, I've had a few clients who need more flexible URL structures than the default /pages system allows |
@aej11a the example will have pretty much the same features but leverages other features to achieve the intended result so that you get much more flexibility, the most common feedback around the i18n feature has been "I want to do x in a different way" so it made more sense to leave it out of the built-in features and instead provide an example to achieve the same. I can't share the full example yet because there's a few changes needed in order to mirror the incoming locale matching. The short of it is:
// app/[lang]/layout.ts
export function generateStaticParams() {
return [{ lang: 'en' }, { lang: 'nl' }, { lang: 'de' }]
}
export default function Layout({children, params}) {
return <html lang={params.lang}>
<head></head>
<body>{children}</body>
</html>
}
// app/[lang]/page.ts
export default function Page({params}) {
return <h1>Hello from {params.lang}</h1>
}
// app/[lang]/blog/[slug]/page.js
export function generateStaticParams({params}) {
// generateStaticParams below another generateStaticParams is called once for each value above it
const lang = params.lang
const postSlugsByLanguage = getPostSlugsByLanguage(lang)
return postsByLanguage.map(slug => {
// Both params have to be returned.
return {
lang,
slug
}
})
}
export default function BlogPage({params}) {
return <h1>Dashboard in Language: {params.lang}</h1>
} |
@timneutkens thanks a lot for your example. one thing missing is the actual code for "Reading lang in page/layout:", as it's showing the axact same code block as for the point before ("Root layout with generateStaticParams:"). |
@oezi good catch! I copied the wrong block from my notes indeed, fixed! |
@leerob My apologies, I didn't know about the caching section in the docs and should have checked—thanks for pointing this out! I've edited my comment above to be accurate. |
Hi @leerob Thanks for the example.Our requirement is as follows:
How can this be achieved ? Since [lang] folder is above all the folders in your example, i am unable to figure this out. |
@prashantchothani Our plan is to create a middleware that:
This way the user sees domain.com/flights but the middleware updates it server side to domain.com/en/flights |
Thanks a lot. I will try doing this. If you succeed please could you let me know the code snippet for this ? And i think, you need to redirect request with /* without any [lang] to /en/* i guess. What you mentioned is other way around. |
No. I've created a quick example: Here you have a default locale, e.g. the url's are Trying to access http://localhost:3000/en/products will result in a redirect to http://localhost:3000/products middleware.ts import { NextRequest, NextResponse } from 'next/server'
const defaultLocale = 'en'
let locales = ['de']
export function middleware(request: NextRequest) {
// Check if there is any supported locale in the pathname
const pathname = request.nextUrl.pathname
// Check if the default locale is in the pathname
if (pathname.startsWith(`/${defaultLocale}/`) || pathname === `/${defaultLocale}`) {
// e.g. incoming request is /en/products
// The new URL is now /products
return NextResponse.redirect(
new URL(pathname.replace(`/${defaultLocale}`, pathname === `/${defaultLocale}` ? '/' : ''), request.url)
)
}
const pathnameIsMissingLocale = locales.every(
(locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
)
if (pathnameIsMissingLocale) {
// We are on the default locale
// Rewrite so Next.js understands
// e.g. incoming request is /products
// Tell Next.js it should pretend it's /en/products
return NextResponse.rewrite(
new URL(`/${defaultLocale}${pathname}`, request.url)
)
}
}
export const config = {
matcher: [
// Skip all internal paths (_next)
'/((?!api|_next/static|_next/image|assets|favicon.ico).*)',
],
} |
I tried to setup a NextJS 13 project including internationalisation with the example on Github provided by Vercel.
It seems I can finally start migrating NextJS projects to the app directory and make use of all the awesome new features! :) |
Check my answer above. This solves the issue with loading local images with relative paths. |
Hi everyone, over the last few days I wrote a guide based on the official examples provided showing how to set up localized routing, automatic locale detection, static generation, and content translation. Here's the link, I hope it helps! I learned a lot writing it: https://dev.to/ajones_codes/the-ultimate-guide-to-internationalization-i18n-in-nextjs-13-ed0 (Not sure if I'm allowed to post this here - there's no self-promotion other than a single Twitter link at the end of the article, but I'd be happy to take down the link if needed!) |
While this should definitely work (many guides out there are applying the same concepts but with packages such as react-i18next) there is still something that's a no go for me, you have to pass the language parameter as a prop to child components and even to the useTranslation hook (if you use it), there is no easy way to retrieve the current locale otherwise. Also it looks like on server side you cannot use singletons for this use case (every guides shows a custom useTranslation hook which init a new instance of react-i18next for example) I know the split between server and client components has to increase complexity but this looks very unpractical to me. Should this be adressed by external packages directly or is there a need for developments on nextjs to make it as efficient to develop with as before too ? |
@TCM-dev I see that |
Hey fellows! We have an existing Next.js 12 site which uses
Same was pointed out by @fernandojbf and @guttenbergovitz earlier in the following posts. I'm not sure if that was addressed already. If so, can someone link the solution? If not, is this issue open somewhere else separately so that I could track?
Thanks a lot in advance. |
I agree to this, that's the reason why I went for a SSR-only approach for now. By doing that there's a workaround and the locale can be retrieved deeply from within the component tree by reading from a cookie or header.
I experimented with it, but unfortunately couldn't find a reliable way on how to use it with Next.js: #44222. I'm also not sure where a good place to add it would be, since there's no natural root like |
Hi everyone, since we have an official guide and example, I think the original request has been fulfilled on this issue, so I am closing it. We understand if you have specific/requirements or questions for your specific use case. If you think something is missing from the guide/example above, you can open a new issue or add feedback directly on the guide page via Preview Comments, and we will review them. Thanks! |
This example didn't work for me. I keep getting a static to dynamic error https://nextjs.org/docs/messages/app-static-to-dynamic-error I'd also like to table domain based locale detection being an important feature. Currently we use next-18next and it works well with pages, using an edge function to re-route to a domain based on locale. This keeps Urls clean of locale e.g. know /en_GB/ etc. |
Hello!, I'm getting this error with electron + nextjs with that example. Any chances someone has worked on this? TypeError: Invalid URL: http://undefined:undefined/?__nextDefaultLocale= |
Hi, after many attempts, I can't get a good result in my use case: I'm trying to use [lang] as indicated in the documentation, but I need one of the segments to be with SSR in the fetching (cache: no-store + revalidate: 0). The problem is that whenever I try to load the [lang]/my-ssr-segment, Next JS warns me that in runtime it tried to change from static to dynamic. What should I do in this case? |
@damianricobelli take a look at this issue maybe and feel free to comment: #44712 |
It doesn't work for me. The main problem I've got right now and can't get past is those images... Better approach I found is to check if it's image request like this: if(request.headers.get("sec-fetch-dest") === 'image') but I'm not able to return the image anyway. How to return proper image response? Or maybe that's because I've got the images in /public/logo/... |
The main problem is that i want an optional parameter for default language (Like previous version of next.js) and required for other languages, All solutions didnt support this feature yet. |
You can solve this with a rewrite when the default locale matches. The |
I came up with a different approach, since I missed a comment in the provided
where
|
About the images and other files on the public directory, look at this code below: https://nextjs.org/docs/advanced-features/i18n-routing const PUBLIC_FILE = /\.(.*)$/
if (
req.nextUrl.pathname.startsWith('/_next') ||
req.nextUrl.pathname.includes('/api/') ||
PUBLIC_FILE.test(req.nextUrl.pathname)
) {
return
} I tried, and everything worked very well. |
could you share a demo repo / codepen? |
@l4b4r4b4b4 Here is my import { match as matchLocale } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import { i18n } from './i18n-config'
function getLocale(request: NextRequest): string | undefined {
// Negotiator expects plain object so we need to transform headers
const negotiatorHeaders: Record<string, string> = {}
request.headers.forEach((value, key) => (negotiatorHeaders[key] = value))
// Use negotiator and intl-localematcher to get best locale
let languages = new Negotiator({ headers: negotiatorHeaders }).languages()
const locales: string[] = i18n.locales.slice()
return matchLocale(languages, locales, i18n.defaultLocale)
}
export function middleware(request: NextRequest) {
// Skip next internal and image requests
if (
request.nextUrl.pathname.startsWith('/_next') ||
request.nextUrl.pathname.includes('/api/') ||
/\.(.*)$/.test(request.nextUrl.pathname)
) {
return
}
// Check if there is any supported locale in the pathname
const pathname = request.nextUrl.pathname
const pathnameIsMissingLocale = i18n.locales.every(
locale => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
)
// Let's redirect if there is no locale
if (pathnameIsMissingLocale) {
const locale = getLocale(request)
return NextResponse.redirect(new URL(`/${locale}/${pathname}`, request.url))
}
}
export const config = {
// Matcher ignoring `/_next/` and `/api/`
matcher: ['/((?!api|_next/static|_next/image).*)'],
} |
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you. |
Verify canary release
Provide environment information
Operating System:
Platform: win32
Arch: x64
Version: Windows 10 Home
Binaries:
Node: 16.15.0
npm: N/A
Yarn: N/A
pnpm: N/A
Relevant packages:
next: 13.0.1-canary.0
eslint-config-next: 13.0.0
react: 18.2.0
react-dom: 18.2.0
What browser are you using? (if relevant)
Chrome
How are you deploying your application? (if relevant)
Local
Describe the Bug
Setting up i18n test in next.config as follows:
I've deleted pages and added a few files into the new /app folder to test
Creating a simple component like so:
I'm not seeing any locale information provided via the props. I was thinking this would be provided on the server side for rendering locale specific data on the server.
Expected Behavior
I would expect to be passed the current locale for use within sever components layouts/pages.
Link to reproduction
https://github.com/jimmyjamieson/nextjs-13-ts
To Reproduce
npm dev, check output of props, locale in layout
The text was updated successfully, but these errors were encountered: