概要
Next.js単体で多言語対応できるようになってるので、試してみました。(ちなみに、以前まではNext.jsの多言語対応には next-i18-next を使っていました。) 設定は公式の通りとても簡単で、各コンポーネント内でのlocale情報はuseRouterから取得できるようになっています。 1点、HTMLタグに lang を設定するのをどうやろうか少し考えた結果、無駄骨だったのでメモを残しておきます。
余談
htmlのlangをみて、日本語のときだけ、一部テキストにtext-align: justify;をかけたりします。
html[lang=ja] .text-justify {
    text-align: justify;
}
結論
_document.tsのrender() で __NEXT_DATA__からlocaleを取得できる。
pages/_document.tsximport Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
  DocumentInitialProps,
} from 'next/document'
class imDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<DocumentInitialProps> {
    const initialProps = await Document.getInitialProps(ctx)
    return initialProps
  }
  render(): JSX.Element {
    const { locale } = this.props.__NEXT_DATA__ 
    return (
      <Html lang={locale} dir="ltr"> { 
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
export default MyDocument
今まで__NEXT_DATA__をちゃんと理解してなかった。
サーバーサイドからのデータがここに入るらしく、ページのソースから見えちゃうので、逆に出ちゃ駄目なデータが入らないように気を付けないと。
おまけ、最初にやったこと
ctxからlocaleを取得して render に渡そうと考えた結果
pages/_document.tsximport Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
  DocumentInitialProps,
} from 'next/document'
type Props = DocumentInitialProps & {
  locale: string
}
class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<Props> {
    const initialProps = await Document.getInitialProps(ctx)
    return {...initialProps, locale: ctx?.locale || 'ja' } 
  }
  render(): JSX.Element {
    return (
      <Html lang={this.props.locale} dir="ltr"> { 
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    )
  }
}
export default MyDocument