问题
I'm working on a multilange static landing page in a Next.Js project. My goal is to have the following structure:
- / -> English Home page
- /de -> German Home page
- /it -> Italian Home page
I'm building it in the following way:
pages/index.js
export default function Home() {
return <div>English Homepage</div>
}
pages/de.js
export default function Home() {
return <div>German page</div>
}
In order to make the website accessible, I would like to set html lang accordingly.
pages/_document.js
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang={???}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
How can I specify the language per page?
I tried with getInitialProps
, but that forces my website to be SSR.
回答1:
You are indeed right about using getInitialProps
. Unlike getInitialProps
in normal pages that will disable Automatic Static Optimization, getInitialProps
in _document.js
has no such effect.
It is because Document
is only rendered in the server. Document
's getInitialProps
function is not called during client-side transitions, nor when a page is statically optimized. More about its technical details
That's why you can use it to inject a lang
prop into pages and still get the benefits of static optimization.
// _document.js
...
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
const { pathname } = ctx;
const lang = pathname.startsWith("/de") ? "de" : "en";
return { ...initialProps, lang };
}
...
To have the lang
attribute also updated during client-transitions, you have to also set up an useRouter
hook in _app.js
to watch the route change:
// _app.js
import React, { useEffect } from "react";
import { useRouter } from "next/router";
export default function MyApp({ Component, pageProps }) {
const { pathname } = useRouter();
const lang = pathname.startsWith("/de") ? "de" : "en";
useEffect(() => {
document.documentElement.lang = lang;
}, [lang]);
return <Component {...pageProps} />;
}
I have created this CodeSandbox for you as a demo.
Download it to your local machine and inspect the code. After npm install
, run npm run build
. You will see from the Build Logs that both "/" and "de" are static. Run npm start
and view the page source, you will see the lang
attribute is set properly in the HTML.
回答2:
Hey maybe not the best solution, but should work, you can use dangerousAsPath
prop on _document.jsx
page and decide the lang
based on the path.
render() {
return (
<Html lang={this.props.dangerousAsPath === '/de' ? 'de' : 'en'}>
{/* ... */}
</Html>
)
}
Again there probably should be a better solution for this. Cheers.
Edit:
There might be a chance that dangerousAsPath
will be removed, if so you can use this.props.__NEXT_DATA__.page
until you find a better option.
回答3:
For your example, if you assume your urls will always follow this pattern
https://somedomain.com/{lang}/everything-else
,
then you could extract the lang
from the url like:
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
// `ctx.req.path` would be of pattern: `/{lang}/everything-else`
// ctx.req.path.split('/') --> ['', 'lang', 'everything-else']
const locale = ctx.req.path.split('/')[1]
return { ...initialProps, locale }
}
render() {
return (
// get the language
<Html lang={this.props.locale}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
As a side-note, I'd suggest exploring next-i18next package, for a more standard way of implementing localization in next.js
来源:https://stackoverflow.com/questions/62297280/dynamic-html-lang-property-in-statically-generated-next-js-pages