DEV Community

Cover image for I implement Next-Intl into my Portfolio (Next JS & App Router)
Bramsurya Johannes Paulus
Bramsurya Johannes Paulus

Posted on • Edited on

I implement Next-Intl into my Portfolio (Next JS & App Router)

Before I dive into implementing the new feature (Next-Intl) I added to my portfolio, you might want to check it out first at my portfolio.

Internationalization (often abbreviated as i18n) is an important aspect of web development, especially for websites that cater to a global audience. Here are some key features and benefits of using internationalization on your website:

  1. Language Localization: Internationalization allows your website to be translated into different languages. This makes your content accessible to users around the world, regardless of their native language.
  2. Improved User Experience: By providing content in a user’s native language and adhering to their cultural norms, you enhance their experience and engagement with your website.
  3. SEO Benefits: Search engines favor websites that cater to a global audience. By having your website content available in multiple languages, you can improve your search engine rankings.

Because I'm using Next JS as my tech to build my portfolio, I use the Next-Intl so it will be compatible with my website. To implement Next-Intl as I did in my portfolio you can follow this step(I will demonstrate this with my web code):

  1. Add Next-Intl into your application
   npm i next-intl
Enter fullscreen mode Exit fullscreen mode
  1. Create this folder structure
   ├── locales (1)
   │   ├── en.json
   │   └── ... // your others locales file (e.g. id.json)
   ├── next.config.js (2)
   ├── i18n.ts (3)
   ├── middleware.ts (4)
   └── app
       └── [locale]
           ├── layout.tsx (5)
           └── page.tsx (6)
Enter fullscreen mode Exit fullscreen mode

You can follow my folder structure example
Folder Structure Example

  1. Setup the files

    1. Add JSON files in your project based on locales(e.g. en.json, id.json)

    en.json

      "Project": {
         "label": "My Projects"
      },
    
    1. Add this code to your next.config.js

    next.config.js

      // @ts-check
      const createNextIntlPlugin = require('next-intl/plugin')
    
      const withNextIntl = createNextIntlPlugin()
    
      /** @type {import('next').NextConfig} */
    
      const config = {}
    
      module.exports = withNextIntl(config)
    
    1. Add this code to your i18n.ts

    i18n.ts

      import { notFound } from 'next/navigation'
      import { getRequestConfig } from 'next-intl/server'
    
      const locales = ['en', ...] // Add your other locales here
    
      export default getRequestConfig(async ({ locale }) => { 
         // Validate that the incoming `locale` parameter is valid 
         if (!locales.includes(locale as any)) notFound()
    
         return {
            messages: (await import(`./locales/${locale}.json`)).default,
         }
      })
    
    
    1. Add this code to your middleware.ts

    middleware.ts

       import createMiddleware from 'next-intl/middleware'
    
       export default createMiddleware({
       // A list of all locales that are supported
       locales: ['en', ...], // Add your other locales
    
       // Used when no locale matches
       defaultLocale: 'en',
       })
    
       export const config = {
       // Match only internationalized pathnames
       matcher: ['/', '/(id|en)/:path*'],
       }
    
    1. Add this code to your app/[locale]/layout.tsx

    app/[locale]/layout.tsx

    ```
    import { NextIntlClientProvider } from 'next-intl'
    import { getMessages } from 'next-intl/server'
    
    type Props = {
       children: ReactNode
       params: { locale: string }
    }
    
    export default async function RootLayout({
      children,
      params: { locale },
    }: Props) {
        const messages = await getMessages()
        return (
           <html lang={locale}>
             <body>
               <NextIntlClientProvider messages={messages}
                   {children}
               </NextIntlClientProvider>
             </body>
           </html>
        )
    }
    ```
    
    1. Call your translation using useTranslation in your page components or anywhere else!

      e.g. Projects.tsx

      import { useTranslations } from 'next-intl'
      
      export default function Projects() {
         const t = useTranslations('Project')
      
         return (<p>{t('label')}</p>)
      }
      

You can make a language toggler button to switch language as you wish, but before that you guys need to make a routing using Next-Intl so follow this step:

  1. Create config.ts on your root folder and add this code

config.ts

   export const locales = ['en', 'id'] as const

   // Use the default: `always`
   export const localePrefix = undefined
Enter fullscreen mode Exit fullscreen mode
  1. Create navigation.ts on your root folder and add this code

navigation.ts

```
import { createSharedPathnamesNavigation } from 'next-intl/navigation'
import { locales, localePrefix } from './config'

export const { Link, redirect, usePathname, useRouter } =
   createSharedPathnamesNavigation({
      locales,
      localePrefix,
   })
```
Enter fullscreen mode Exit fullscreen mode
  1. If you done two of the previous step you can make the language button toggler

    LangToggler.tsx

    'use client'
    
    import { useTransition } from 'react'
    import { useRouter, usePathname } from '../navigation'
    import { useLocale } from 'next-intl'
    
    import inaIcon from '@/public/ina-icon.svg'
    import enIcon from '@/public/en-icon.svg'
    import Image from 'next/image'
    
    export default function LangToggler() {
        const router = useRouter()
        const [isPending, startTransition] = useTransition()
        const pathname = usePathname()
        const locale = useLocale()
    
        const nextLocale = locale === 'en' ? 'id' : 'en'
    
        function onButtonClick() {
            startTransition(() => {
                 router.replace(pathname, { locale: nextLocale })
            })
        }
    
        return (
           <button
               disabled={isPending}
               onClick={onButtonClick}
           >
               <Image
                  src={locale === 'en' ? inaIcon : enIcon}
                  alt='language flag icon'
                  className='w-4'
               />
           </button>
        )
    }
    
    

Voila, you have done adding Next-Intl to your application. This is an example of my portfolio website

My Web with English Language

My Web with Indonesian Language

Happy coding guys, Thankyou!

Top comments (5)

Collapse
 
amannn profile image
Jan Amann

The animated language toggle is 💯!

Collapse
 
bramsuryajp profile image
Bramsurya Johannes Paulus

Thankyou very much, appreciate it!!😁👐