DEV Community

Vu Hoang Lam
Vu Hoang Lam

Posted on

Integrating Multi-Language in Next.js with Custom Hooks and Redux

Image description

Today, I'll walk you through implementing multi-language support in Next.js using only custom hooks and Redux. The beauty of this method is its compatibility with any version of Next.js or even React.js. Let's dive in!

Firstly, let's set up a Redux reducer using Redux Toolkit called LanguageStore:

import { createSlice } from '@reduxjs/toolkit'

export const LanguageStore = createSlice({
    name: 'LanguageStore',
    initialState: {
        language: 'vi',
    },
    reducers: {
        setLanguage: (state, actions) => {
            state.language = actions.payload
        },
    }
})

export const { setLanguage } = LanguageStore.actions

export default LanguageStore.reducer;
Enter fullscreen mode Exit fullscreen mode

Next, create language data files. I've prepared two language files: vi.json for Vietnamese and en.json for English.

Here's an example of vi.json:

{
    "about": "Giới thiệu",
    "menu": "Thực đơn",
    "news": "Tin tức",
    "gallery": "Thư viện",
    "order": "Đặt bàn ngay",
}
Enter fullscreen mode Exit fullscreen mode

And en.json:

{
    "about": "About us",
    "menu": "Menu",
    "news": "News",
    "gallery": "Library",
    "order": "Book Now",
}
Enter fullscreen mode Exit fullscreen mode

Now, let's create useLanguage.js, a custom hook:

import { useSelector } from 'react-redux';
import vi from "../helper/translates/vi.json"
import en from "../helper/translates/en.json"
const useLanguage = () => {
    const LanguageStore = useSelector((state) => state?.LanguageStore)
    const listLangue = {
        en: en,
        vi: vi,
    }

    const t = (text_params) => {
        let text = ''
        const langValue = LanguageStore?.language
        const getTextList = listLangue?.[langValue]
        if (listLangue?.[langValue]) {
            if (getTextList?.[text_params]) {
                text = getTextList?.[text_params]
            }
        }
        return text
    }
    return {
        t
    };
};

export default useLanguage;
Enter fullscreen mode Exit fullscreen mode

Great! Now, let's put it to use:

// Navbar.jsx
import useLanguage from "@/app/hooks/useLanguage";
import { setLanguage } from "@/app/store/reducer/LanguageStore";
import { useDispatch, useSelector } from "react-redux";
export const linkList = [
    {
      id: 1,
      url: "/ve-chung-toi",
      languageFlag: "about",
      title: "Giới thiệu",
    },
    {
      id: 2,
      url: "/menu",
      languageFlag: "menu",
      title: "Thực đơn",
    },
    {
      id: 3,
      url: "/tin-tuc",
      languageFlag: "news",
      title: "Tin tức",
    },
    {
      id: 4,
      url: "/thu-vien",
      languageFlag: "gallery",
      title: "Thư viện",
    },
  ];
function Navbar() {
  const { t } = useLanguage();
  const { language } = useSelector((state) => state.LanguageStore);
 const handleLanguageChange = (value) => {
    dispatch(setLanguage(value.value));
  };
  const languageOptions = [
    {
      value: "vi",
      label: (
        <Stack direction={"row"} alignItems="center" gap={"4px"}>
          <Image alt="" src={"/vn-language.svg"} width={24} height={24} />
          <Typography>VN</Typography>
        </Stack>
      ),
    },
    {
      value: "en",
      label: (
        <Stack direction={"row"} alignItems="center" gap={"4px"}>
          <Image alt="" src={"/en-language.svg"} width={24} height={24} />
          <Typography>EN</Typography>
        </Stack>
      ),
    },
  ];
return (
   <>
            {linkList.map((item) => (
              <Link 
                   href={item.url} 
                   key={item.id}>
                <Typography
                  textTransform={"uppercase"}
                  color={"#88231F"}
                  fontWeight={router.pathname === item.url ? 700 : 400}
                  fontSize={"14px"}
                  lineHeight={"24px"}
                >
                  {/* {item.title} */}
                  {t(item.languageFlag)}
                </Typography>
              </Link>
            ))}
            <CustomSelect
              options={languageOptions}
              defaultValue= 
                  {languageOptions.find((item) => 
                    item.value === language)}
              handleChange={handleLanguageChange}
            />
   </>
  )
}
Enter fullscreen mode Exit fullscreen mode

And that's it! You're all set to use multi-language support in your Next.js app. I hope you find this tutorial helpful. Happy coding!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Cloudinary image

Optimize, customize, deliver, manage and analyze your images.

Remove background in all your web images at the same time, use outpainting to expand images with matching content, remove objects via open-set object detection and fill, recolor, crop, resize... Discover these and hundreds more ways to manage your web images and videos on a scale.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay