typescriptnext.jsi18nextnext-i18next

proper getServerSideProps syntax for Typescript next.js + i18n


I'm struggling with next-i18next integration in a NextJS Typescript project - has nearly no recent examples anywhere. I've already configured internationalized routing, but I can't properly setup i18next as long as getServerSideProps syntax is bothering me.

I don't know much about Typescript, and am not familiar with types declarations yet.

The code looks like this, mostly copied from next-i18next documentation :

### index.tsx

// rest of index.tsx...

export const getServerSideProps: GetServerSideProps = async ({locale}) => ({
  props: {
    ...await serverSideTranslations(locale, ['common', 'header']),
  },
})

export default Home

An error is thrown in my IDE about "locale". Even though I'm using getServerSideProps, i'm not even sure that it is the best solution for a mostly static project, but it seems I can't avoid it if I'm planning a SSR in the end. A simple way to deliver correctly translated content + having a matching URL locale would be awesome.


Solution

  • The typing error about locale is correct, because it can be empty when i18n isn't set up. See discussion here: https://github.com/isaachinman/next-i18next/issues/1307

    There are multiple ways to deal with this issue

    1. Cast the locale as string
    export const getServerSideProps: GetServerSideProps = async ({ locale }) => ({
      props: {
        ...await serverSideTranslations(locale as string, ['common', 'header']),
      },
    })
    
    1. Define your own GetServerSideProps type where locale isn't optional and use that one.
    type CustomGetServerSideProps<
      P extends { [key: string]: any } = { [key: string]: any },
      Q extends ParsedUrlQuery = ParsedUrlQuery
    > = (context: GetServerSidePropsContext<Q>) => Promise<GetServerSidePropsResult<P>>
    
    type GetServerSidePropsContext<Q extends ParsedUrlQuery = ParsedUrlQuery> = {
      req: IncomingMessage & {
        cookies: NextApiRequestCookies
      }
      res: ServerResponse
      params?: Q
      query: ParsedUrlQuery
      preview?: boolean
      previewData?: PreviewData
      resolvedUrl: string
      locale: string // This is where the magic happens.
      locales?: string[]
      defaultLocale?: string
    }
    
    export const getServerSideProps: CustomGetServerSideProps = async ({ locale }) => ({
      props: {
        ...await serverSideTranslations(locale, ['common', 'header']),
      },
    })
    

    I'm using the second option myself because that way I don't have to cast the same variable all the time, which is also already a string.