Skip to main content

Command Palette

Search for a command to run...

[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

Updated
4 min read
[Next.js] 나만의 학습 블로그 만들기#3-다국어 지원 (Feat.next-i18next)

오늘은 다국어 지원 가능한 기능 구현 과정을 적어보려고 한다.

원래는 댓글기능보다 먼저 구현하려고 했는데 ,, 갑자기 댓글기능 알아보다가 재밌어서 먼저 끝내버렸다,,,🙄

시작하기 전에 정말 어려웠다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 어려움이 많아서 기능 적용하는 데 시간이 꽤 걸렸다 ,,,

다국어 지원 기능

  • 나는 영어랑 일본어를 추가해줬다 ! (해외취업도 관심 있기 때문에 나중에 이력서 낼 때 도움이 되지 않을까? ..🤭)

다국어 구현 방법

구현 방법에는 크게 두가지가 있다.

  • 직접 구현

    장점 프로젝트 특성에 맞게 커스터마이징 가능
    단점: 기능 구현에 시간과 노력이 많이 필요

  • 라이브러리 사용

    장점: 빠르고 안정적인 구현 가능
    단점: 라이브러리 학습 필요, 프로젝트에 맞게 설정해야 함

나는 라이브러리를 사용했다. 아무래도 next 프레임워크 사용은 처음이기도 하고 아무래도 다국어 지원을 위해서는 직접 구현보다는 안정적이고 널리 쓰이는 라이브러리인 next-i18next가 좋다고 판단했기 때문이다.

추가로 댓글 기능을 Giscus를 사용해서 구현했기 때문에 찰떡궁합쓰-!

  • Giscus는 GitHub Discussions를 댓글 시스템으로 쉽게 붙일 수 있게 해주는 서비스

  • next-i18next는 Next.js에서 다국어 지원을 편하게 해주는 라이브러리


구현 과정

//설치
npm install next-i18next react-i18next i18next

next-i18next.config.js 파일 생성

const nextI18NextConfig = {
  i18n: {
    defaultLocale: "ko",
    locales: ["ko", "en", "ja"],
    localeDetection: true,
  },
  ns: ["common"],
  defaultNS: "common",
  react: {
    useSuspense: false,
  },
};

export default nextI18NextConfig;

next.config.mjs 설정

const nextI18NextConfig = {
  i18n: {
    locales: ["ko", "en", "ja"],
    defaultLocale: "ko",
  },
};

export default nextI18NextConfig;

Comments

import Giscus from "@giscus/react";
import { useTranslation } from "next-i18next";

export default function Comments() {
  const { i18n } = useTranslation();
  const lang = ["ko", "en", "ja"].includes(i18n.language)
    ? i18n.language
    : "en";

  return (
    <Giscus
      lang={lang}
    />
  );
}

fallback인 경우에는 영어로 처리하게 해줬다!

app.js

import { appWithTranslation } from "next-i18next";
import nextI18NextConfig from "../../next-i18next.config";
function App() {
  return (
...
  );
}
export default appWithTranslation(App, nextI18NextConfig);

appWithTranslation

  • next-i18next에서 제공하는 HOC(Higher Order Component) 이걸 감싸야 Next.js 앱 전체에서 다국어 컨텍스트와 기능을 사용할 수 있으며, 모든 페이지와 컴포넌트에서 useTranslation 훅 쓸 수 있게 해줬다.

index.js

import Comments from "@/components/Comments";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import nextI18NextConfig from "../../next-i18next.config";

export async function getStaticProps({ locale }) {
  return {
    props: {
      ...(await serverSideTranslations(locale, ["common"], nextI18NextConfig)),
    },
  };
}
  • getStaticProps 에서 serverSideTranslations 호출

    • 현재 요청된 locale에 맞춰 필요한 번역 리소스를 빌드 타임에 미리 불러와 페이지에 주입해줬다. 이게 있어야지SSR시점에 번역 텍스트가 반영된다.
  • Comments 컴포넌트 렌더링:

    • 앞서 말한 Giscus 댓글 컴포넌트를 다국어 설정과 함께 사용해줬다.

겪었던 트러블 슈팅 📄

여기까지 보면 세팅 하는건데 뭐가 어려웠다는거야?! 라는 생각을 할 수 있지만,, gif에서 보면 언어를 선택해도 이름이 바뀌지 않는 문제를 오랜시간동안 해결하지 못 했다…

콘솔로 찍어봤을때는 ja, en 이렇게 잘 찍히는데 정작 반영이 안된것,,,

왜 이런 문제가 생겼는지 알아봤는데

Next.js에서는 서버에서 렌더링된 HTML과 클라이언트에서 렌더링된 HTML이 다르면 경고가 뜨는데 그걸 Hydration Mismatch라고 한다.

쉽게 말해서

  • 서버에서는 i18n.language'en'이라고 판단해서 <span>English</span> 렌더링

  • 근데 클라이언트에서는 브라우저 언어에 따라 'ja'로 바뀌어서 <span>日本語</span>로 바뀜
    → React가 "어? 서버랑 클라이언트에서 HTML 다르네!" 라고 경고를 띄움

문제이다.

해결 방법

//Header.jsx
{!isMobile && <span suppressHydrationWarning>{t("name")}</span>}

이를 방지하기 위해 <span suppressHydrationWarning> 속성을 사용하여 해당 경고를 억제했다.
(클라이언트 사이드에서 정확한 언어가 적용되는 상황에서 유효한 방법!)

잘 반영된다,, 🤭

조회수도 반영해보자 -!

public/locales/en,ko,ja 각 언어에 해당하는 언어를 여기에 넣어주면 된다.

이런식으로

//TotalView.js
import { useEffect, useState } from "react";
import { getTotalViews } from "../../lib/incrementView";

export default function TotalView() {
  const [total, setTotal] = useState(0);

  useEffect(() => {
    getTotalViews()
      .then(setTotal)
      .catch(() => setTotal(0));
  }, []);

  return (
    <div className="text-right sm:text-sm text-xs text-gray-600 dark:text-gray-400 px-4 ml-auto">
      조회수 | <span className="font-semibold">{total.toLocaleString()}회</span>
    </div>
  );
}

지금은 이렇게 하드코딩으로 되어 있어서 당연히 언어를 선택해도 계속 조회수 | 숫자 회 이렇게 뜨는 것!

수정해보자

//TotalView.js
import { useTranslation } from "next-i18next";

export default function TotalView() {
  const { t } = useTranslation("common");

  return (
    <div className="text-right sm:text-sm text-xs text-gray-600 dark:text-gray-400 px-4 ml-auto">
      {t("views")} |{" "}
      <span className="font-semibold">
        {total.toLocaleString()}
        {t("views_suffix")}
      </span>
    </div>
  );
}

잘 반영된다 😊

🌱 느낀점

Next.js로 블로그를 만들면서 처음으로 다국어 지원을 구현해봤는데 생각보다 고려해야 할 부분이 많아서 꽤 흥미로운 경험이었다.
특히 next-i18next를 사용하면서 SSR 클라이언트 hydration 문제 Giscus처럼 외부 라이브러리와의 언어 연동 등 다양한 상황을 마주했다.

처음에는 단순히 JSON에 번역만 넣으면 끝날 줄 알았지만 실제로는 페이지 렌더링 시점, 클라이언트와 서버의 불일치, suppressHydrationWarning, ready 상태 체크 같은 세세한 부분까지 신경 써야 했다…(솔직히 어려웠음😬)

조회수 표시 같은 UI 요소도 하드코딩된 텍스트를 하나씩 번역 키로 바꾸는 과정이 신경써야 할 부분이 꽤 많지만 결과적으로 완성된 다국어 UI를 보니 꽤 뿌듯했다.

그리고 무엇보다 재밌었다!!!
단순히 기능을 구현하는 데 그치지 않고 실제 사용자 입장에서 언어에 따라 어떻게 경험이 달라지는지 고민하는 과정 자체가 즐거웠다. 앞으로 모든 프로젝트에서도 다국어 기능은 꼭 넣어보고 싶을 정도로 매력적인 작업이었다.(처음엔 진짜 좀 힘듬)..

More from this blog

[회고] 풀스택 개발자로 (곧) 1년...

정말 정말 오랜만에 글을 작성한다 🤭 나는 현재 개발자로 취업한 지 거의 1년이 다 되어간다. 이제 10개월임 ! 처음에는 무조건 프론트엔드 개발자로 취업할거임!! 풀스택 NO ! 라는 마음으로 준비했던 취업.. 하지만 현실은 풀스택으로 취업하게 되었다. 취업을 하고 나니 여러가지 생각과 감정이 들었고 맨날 회고 적어야지 ~ 적어야지 ~ 했는데 10개

May 29, 20263 min read

[React] 클라이언트에서 이미지를 압축해보자

우리는 서버 비용을 직접 부담하고 있기 때문에 항상 최적화와 비용 절감 방법을 고민하게 된다. 현재 자유게시판이 활성화가 많이 되지는 않았지만 사용자들이 업로드하는 이미지가 평균 5MB 이상일 경우를 대비해서 클라이언트에서 이미지 압축을 진행했다. 웹에서는 크게 두 가지 방법이 있었는데 Canvas API를 직접 사용하는 방법 browser-image-compression 라이브러리를 활용하는 방법 이 있다. 여러 장점을 고려해 brow...

Oct 8, 20252 min read
[React] 클라이언트에서 이미지를 압축해보자

[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

내가 생각하는 프론트엔드 개발자는 단순히 보이는 화면만 구현하는 것을 넘어서 누구나 접근할 수 있는 웹을 만드는 데 중요한 역할을 해야 한다고 생각한다. 실무에 바로 적용하는 웹 접근성 가이드북 이번에 이 책을 받고 프엔들이 읽기에 너무 좋다고 생각해서 블로그에 추천 글까지 적게 되었다 ! 목차 Chatper1. 쉽게 이해하는 접근성 Chapter2. 웹 접근성의 기초 Chapter3. HTML 태그, 의미 있게 사용하기 Chpater4...

Jul 27, 20255 min read
[책 추천] 프론트엔드 개발자라면 반드시 알아야 할 '웹 접근성' 이야기

[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)

댓글기능이 있으면 무조건 재밌을 거 같아서 넣어보려고 한다🤭 아무래도 개발에 관련된 학습 블로그라서 개발자들이 많을 것으로 예상했다 ! 그래서 깃허브 이슈 기반 댓글 시스템을 기반으로 기능을 구현해보려고 한다. 👉🏻 도움이 많이 된 블로그 ! 방법 Giscus | (https://giscus.app) utterances | (https://utteranc.es) 알아봤을 때는 이렇게 두 개가 유명하다고 한다. 그럼 각각의 특징과 장...

Jul 14, 20253 min read
[Next.js] 나만의 학습 블로그 만들기#4 - 댓글 기능(Feat. Giscus)
S

subin-dev-blog

28 posts

끊임없이 배우기 위해 노력합니다. 🌱