DEV Community

Cover image for Multi-language Landing page with Next.js
Sibelius Seraphini for Woovi

Posted on

Multi-language Landing page with Next.js

Woovi master plan is to learn a lot about instant payments at Brazil, and be the best platform of instant payments in the world.

For this to happen everything that we build needs to support multi-languages.

One place that was missing multi-language support was in our landing page that uses Next.js.

Static website with Next.js

Even though Next.js is know because of their server side capabilities, our landing page is just a static website.
We use next export to build our landing page and deploy to CloudFlare Pages and CloudFront.

Next has support to i18n out of the box, but not yet when using next export. So we need to figure it out the solution ourselves.

Our landing page architecture

We build our landing page using two approaches: tsx and MDX.

When a page has many different styles and customization, we built it using React/tsx. Example: https://woovi.com/shopper/

<Typography>           
  {t('Create your free account now')}
</Typography>
Enter fullscreen mode Exit fullscreen mode

For tsx we mainly use t() to translate string literals.

When a page is more about content, like an article, it is written in MDX. MDX is Markdown with support to React components. Example: https://woovi.com/articles/a-woovi-e-a-primeira-plataforma-pix-first-do-mundo/

import { ArticleLayout } from '../../templates/ArticleLayout';

export const meta = {
  title: "Pix Débito Automático - Cobrança Pix com Débito Automático",
}

## Módulo para cobranças automáticas usando Pix

O módulo Woovi

export default ({ children }) => <ArticleLayout meta={meta}>{children}</ArticleLayout>;
Enter fullscreen mode Exit fullscreen mode

For mdx we don't translate using t() because this is a full text, and translation of word by word does not provide a good translation.

When adding multi-language support we need to take this architecture in consideration.

Our approach to Multi-language using Next.js

To make our landing page multi-language we have the following structure:

pages/
pages/en
pages/<another-language>
Enter fullscreen mode Exit fullscreen mode

pages/ is our default language, Portuguese.

We duplicate all the pages inside pages/ to all the languages we are supporting, right now only en, English.

For tsx files it will be translate using t().
For mdx files we duplicate and translate the whole content at once.

We check the pathname of the router to determine what language the page is:

const defaultLang = 'ptBR';

export const getLangFromPathname = (pathname: string) => {
  const langs = ['en', 'ptBR'];

  for (const lang of langs) {
    if (pathname.startsWith(`/${lang}`)) {
      return lang;
    }
  }

  return defaultLang;
}
Enter fullscreen mode Exit fullscreen mode

Inside _app.tsx we have this code to make provide the language from the pathname to a React context

const MyApp = ({ Component, pageProps, router }: NextAppProps<AppProps>) => {
   const lang = getLangFromPathname(router.pathname);

   const { t } = useTranslation(lang);

   return (
     <I18Context.Provider value={{ lang }}>
        {getLayout(<Component {...pageProps} />, { t })}
     </I18Context.Provider>
   )
}
Enter fullscreen mode Exit fullscreen mode

Our custom useTranslation hook reads the language from the context and return the correct t().

export const useI18n = () => {
  return useContext(I18Context) || {};
};

export const useTranslation = (defaultLang = 'ptBR') => {
  const { lang = defaultLang } = useI18n();

  const t: TFunction = (key) => {
    const langs = {
      ptBR,
      en,
    };

    const trans = langs[lang][key];

    if (!trans) {
      if (process.env.NODE_ENV === 'development') {
        // eslint-disable-next-line no-console
        console.log('Missing translation: ', key);
      }
    }

    return trans;
  };

  return { t };
};
Enter fullscreen mode Exit fullscreen mode

Link is another thing that needs to be fixed in a multi-language website.

We created the hook useHrefLang to return the correct href based on current language

export const useHrefLang = (href: string) => {
  const { lang = defaultLang } = useI18n();

  if (href?.startsWith('https://')) {
    return href;
  }

  if (href?.startsWith('http://')) {
    return href;
  }

  if (lang === defaultLang) {
    return href;
  }

  if (href?.startsWith(`/${lang}`)) {
    return href;
  }

  return `/${lang}${href}`;
};
Enter fullscreen mode Exit fullscreen mode

In Conclusion

There are much more engineering in a landing page than it looks like.
A multi-language landing page takes more time to maintain, so make sure is the right moment for you to have one.

Check the final result here: https://woovi.com/en


Woovi
Woovi is a Startup that enables shoppers to pay as they like. To make this possible, Woovi provides instant payment solutions for merchants to accept orders.

If you want to work with us, we are hiring!


Photo by Kalen Emsley on Unsplash

Top comments (2)

Collapse
 
tangopj profile image
TangoPJ • Edited

Hello. Where do you use useHrefLang hook?
Did you use 'next export'?
Can you share a link to a git repo with the full example please?

Collapse
 
sibelius profile image
Sibelius Seraphini

You can use like this

const link = '/products';
const linkLanguageAware = useHrefLang(link);

linkLanguageAware would be like this based on the languages, examples:

  • en -> /en/products
  • es -> /es/products