How to set HTML lang attribute dynamically on NextJs Document?

21,504

Solution 1

Using document object the lang attribute can be set like this:

var language= ...
switch (language) {
    case en:  document.documentElement.lang = 'en-us'; break;
    ...
}

This lang attribute will not be set on the initial html, before page is hydrated, but will still pass chrome "hreflang" audit check.

Solution 2

Next 10 supports Internationalized Routing and will add lang dynamically leaving you with:

<Html>
  <Head />
  <body>       
    <Main />
    <NextScript />
  </body>
</Html>

Solution 3

I believe the best solution here is to use a custom ./pages/_document.js file and override the document itself.

import Document, { Html, Head, Main, NextScript } from 'next/document'

class MyDocument extends Document {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx)
    return { ...initialProps }
  }

  render() {
    return (
      <Html lang="en">
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}

export default MyDocument

More explanation can be found here: https://nextjs.org/docs/advanced-features/custom-document

Solution 4

If you use next/head you can set the language to the html tag. Anything that you pass to the Head component will be either placed in the <head> or <html>.

Next Head works similar to React Helmet, so for your case you could do something along these lines:

  • Create a component and import Head from "next/head"
  • Inside the Head tag you add the <html lang={lan} /> to the component.

Then you can pass the desired language to that component, then import the component on the desired pages.

import React from "react"
import Head from "next/head"

const Language = ({title, lang}) => (
  <Head>
    <html lang={lang} />
    <title>{title}</title>
  </Head>
)

export default Language

That html bit will be injected inside the <html> tag.

Note that even if we inject it like this the console will log the following error: TypeError: n is null.

Solution 5

I implemented this by adding this to next.config.js file:

i18n: {
// These are all the locales you want to support in
// your application
locales: ['en-US'],
// This is the default locale you want to be used when visiting
// a non-locale prefixed path e.g. `/hello`
defaultLocale: 'en-US' }

I didn't have the need to create a custom _document.js

Share:
21,504
MiguelSlv
Author by

MiguelSlv

Product Engineer for Printing and Finishing Industry, since 1998. Personal projects: Chat Player - Android App. Outdoor Navigator - Fancy iOS app. Guia Condominio - Self-Managed Home Owners Associations site Home site : https://byte-artisan.com My favorite quote: "Simplicity is the ultimate sophistication" Leonardo da Vinci

Updated on July 09, 2022

Comments

  • MiguelSlv
    MiguelSlv almost 2 years

    I have a multi language site and need to set up the HTML lang attribute according the language for the each page.

    I try to pass the value in context, but does not update when page changes.

    Here the current code:

    import Document, { Html, Head, Main, NextScript } from 'next/document'
    import GlobalContext , {eLanguage }from '../components/GlobalContext' //my global context 
    
    export default class MyDocument extends Document {
    
    static async getInitialProps(ctx) {
    
      const initialProps = await Document.getInitialProps(ctx)
      return { ...initialProps }
    }
    static contextType = GlobalContext;
    render() {
    
      console.debug('Started')
      console.debug('language:'+ this.context.language) 
    
      return (
        <Html lang={eLanguage[this.context.language]}> //if the first page loaded as lang 'en' it sets 'en' and apply to all other pages.
          <Head>
          </Head>
          <body>       
            <Main />
            <NextScript />
          </body>
        </Html>
      )
    }
    

    }

    Update: The language of each page can be inferred from the page route

  • MiguelSlv
    MiguelSlv almost 4 years
    I got this error on the console:head-manager.js?0ea4:2 Warning: next-head-count is missing. err.sh/next.js/next-head-count-missing. In either case, that hist is not a way to go.
  • MiguelSlv
    MiguelSlv almost 4 years
    Also note that Html tag is parent of Head tag. i don't thing Head component it means to be used in this way.
  • Gabriel Linassi
    Gabriel Linassi almost 3 years
    Thanks, this is the right answer. Same as provided in the nextjs docs.
  • ArneHugo
    ArneHugo over 2 years
    @GabrielLinassi, this is not quite the same as in the docs, where it says you should do this in _document. Doing it elsewhere technically works, though perhaps you can't rely on it to keep working, and it gives the console waning Warning: next-head-count is missing as mentioned above.
  • Gabriel Linassi
    Gabriel Linassi over 2 years
    @ArneHugo That's right. Thanks for the correction. I checked here on my code and it's defined on the _document as well.
  • Gangula
    Gangula over 2 years
    For future readers, this is not currently supported if you're using SSG via next export - Reference and Documentation
  • JasonGenX
    JasonGenX about 2 years
    careful, that ALONE would get you 404 on every single page.
  • itsjavi
    itsjavi about 2 years
    this is not SEO friendly unfortunately
  • ImanGM
    ImanGM almost 2 years
    @MiguelSlv <Head> component in _document.js is different than <Head> component that we use to update <head> content. <Head> inside _document.js is being imported from 'next/document' and <Head> inside pages are being loaded from 'next/head'