• Home
  • Blogs
© 2023-2024 Bramsurya. All rights reserved.

About this website: built with React & Next.js (App Router & Server Actions), TypeScript, Tailwind CSS, Bun, Framer Motion, Next Internationalization (i18n), React Email & Resend, Axios, Vercel hosting.

June 11, 2024

3 min read

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

#nextjs

#frontend

#beginners

#webdev

3 min read

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
    
  2. 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)
    
    You can follow my folder structure example Folder Structure Example
  3. 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"
      },
      
    2. 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)
      
    3. 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,
         }
      })
      
      
    4. 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*'],
      }
      
    5. 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>
          )
      }
      
    6. 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
    
  2. 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,
       })
    
  3. 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!

Comments (2)

user-amannn-img

Jan Amann

June 12, 2024

The animated language toggle is 💯!

user-bramsuryajp-img

Bramsurya Johannes Paulus

June 12, 2024

Thankyou very much, appreciate it!!😁👐