Support to set <html lang /> from metadata? #49415
Replies: 15 comments 29 replies
-
I would also like to add my support for this feature, and I would also like to request other export async function generateMetadata() {
return {
htmlAttributes: {
lang: "ar-AE",
dir: "rtl",
},
title: "Ahoj",
}
} Here's a summary of the currently available options/workaround we have, to demonstrate why I think we need framework-level support for this. Pattern 1. -
|
Beta Was this translation helpful? Give feedback.
-
Pattern 2. -
|
Beta Was this translation helpful? Give feedback.
-
I think layouts do refresh (via RSC) when their parameters change. The difference is keeping internal state of the component by remounting the component with changing Problem is supporting default I like idea of the dedicated api |
Beta Was this translation helpful? Give feedback.
-
This is a demo what I think could be achieved without middleware. https://middleware-cache-three.vercel.app |
Beta Was this translation helpful? Give feedback.
-
Also looking for a solution for this. As far as I can see, there's now no way to set the lang attribute serverside AND keep a certain component mounted while navigating between locales (e.g. have the |
Beta Was this translation helpful? Give feedback.
-
I have this same issue and find it insane that nextjs doesn't have an answer for this 🤔 |
Beta Was this translation helpful? Give feedback.
-
Same issue here. I need change html attr in children layout component |
Beta Was this translation helpful? Give feedback.
-
It is crazy that there is still not a possible workaround for such an essential issue. |
Beta Was this translation helpful? Give feedback.
-
For the past couple of months the workaround i managed to come up with is to change the layout to this: export default function RootLayout({ children }: { children: React.ReactNode }) {
return <>{children}</>
} and then on page.tsx: return (
<html lang={data.lang ?? "en"}>
<head>
<title>{data.seo.title}</title>
...
</head>
<body>
...
</body>
</html>
) I don't use |
Beta Was this translation helpful? Give feedback.
-
There's a dirty workaround using a global state variable. For example, in export const state = { locale: "en" }; …then you update the variable in import { state } from "@/config";
export default function Page({ params: { locale } }) {
state.locale = locale;
return (
<div>
...
</div>
);
} …and use it in the root layout import { state } from "@/config";
export default function RootLayout({ children }) {
return (
<html lang={state.locale}>
<body>{children}</body>
</html>
);
} This, of course, is a terrible pattern in general, but it works. At the end of the day, the staticly generated HTML has the correct You can find an explanation of this approach in this article and you can also play around with a working version in this repo. |
Beta Was this translation helpful? Give feedback.
-
We are facing the same issue: The content is loaded through a CMS, and the language of the content cannot be determined either by the domain or necessarily by the path. Of course, it’s clear that all content under /en/* is in English, but there are also short URLs where the language is unknown and can/must only be set after fetching the content. How can this issue be resolved? |
Beta Was this translation helpful? Give feedback.
-
You can try this way:
Use it in
|
Beta Was this translation helpful? Give feedback.
-
As an alternative, you can group your routes let me show you by app router hierarchy:
and it is working for me, of course I hope next.js support it by maybe metadata/generateMetadata or built-in components, but for now, It can work for us, I hope so :) |
Beta Was this translation helpful? Give feedback.
-
I've found a workaround for this by using async layout and page, promises, and server-only-context (which uses React
import serverContext from "server-only-context";
export const [getLangResolve, setLangResolve] = serverContext<
(lang: string) => void
>(() => {});
import { setLangResolve } from "./contexts";
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const lang = await new Promise<string>((resolve) => {
setLangResolve(resolve);
setTimeout(() => resolve("en"), 100); // fallback, just in case
});
return (
<html lang={lang}>
<body>{children}</body>
</html>
);
}
import { getLangResolve } from "../contexts";
export default async function Home(props: {
params: Promise<{ lang: string }>;
}) {
const { lang } = await props.params;
getLangResolve()(lang);
return <h1 className="text-6xl">lang {lang}</h1>;
} This basically does the following:
Generally, you can use this approach to pass whatever you want from the page up to the layout. I tested it for race conditions and it's doing great. It has also been on production for a few days and I haven't seen any issues there as well. Check a demo of it here: https://github.com/hdodov/test-nextjs/tree/demo-dynamic-lang @leerob although this workaround seems to do the job, it'd be much better if Next offers a native solution that doesn't require such despicable promise gymnastics. |
Beta Was this translation helpful? Give feedback.
-
Hi, I solved it this way but I am not fully certain about the approach:
Do you see any bad drawback by removing the RootLayout? |
Beta Was this translation helpful? Give feedback.
-
As far as I know you can only set
<html lang={lang} />
in root layout. It can be dynamic from[lang]
route, which is problematic when you want to have a default locale.In my opinion
lang
should be configurable same as other metadata as layout cannot always know before route loads data.This should result in something like
Do you plan tu support this? Or maybe is there a workaround similar to
useServerInsertedHTML
.I would like to avoid unnecessary usage of
middleware.ts
.Beta Was this translation helpful? Give feedback.
All reactions