[codereview] i18n 템플릿화 다국어지원

Suji Kang·2024년 2월 10일

codereview

목록 보기
5/5


i18n 템플릿화

AS-IS (기존 코드):

export default function Portfolio() {
  const languageList = useContext(UserContext)
  
  const firstServices = (
    <div className={styles.first_column_services}>
      <span className={styles.first_span1}>
        <Link href="/laser/thermage">
          {languageList.state.language === 'English' ? 'Thermage' : '써마지'}
        </Link>
      </span>
      <span className={styles.first_span2}>
        <Link href="/laser/morpheus8byinmode">
          {languageList.state.language === 'English'
            ? 'Morspanheus8'
            : '모피우스8'}
        </Link>
      </span>
      <span className={styles.first_span3}>
        <Link href="/laser/inmodeforma">
          {languageList.state.language === 'English'
            ? 'Inmode Forma'
            : '인모드 포르마'}
        </Link>
      </span>
      <span className={styles.first_span4}>
        <Link href="/laser/inmodeminifx">
          {languageList.state.language === 'English'
            ? 'Inmode Mini FX'
            : '인모드 미니 FX'}
        </Link>
      </span>
      <span className={styles.first_span5}>
        <Link href="/injection/neuro">
          {languageList.state.language === 'English'
            ? 'Neuromodulator'
            : '뉴로모듈레이터'}
        </Link>
      </span>
    </div>
  )

const initialState = {
  language: 'English'
};
const reducer = (state, action) => {
  switch (action.type) {
    case 'KOREAN':
      return { ...state, language: 'Korean' };
    case 'ENGLISH':
      return { ...state, language: 'English' };
      default:
      return initialState;
  }
};

export const UserContext = createContext(reducer);

export default function App({ Component, pageProps }) {
  const [state, dispatch] = useReducer(reducer, initialState);

TO-BE (개선된 코드):

import { useTranslation } from 'next-i18next'

export default function Portfolio() {
  const { t } = useTranslation('home')

const firstServices = (
    <div className={styles.first_column_services}>
      <span className={styles.first_span1}>
        <Link href="/laser/thermage">{t('Thermage')}</Link>
      </span>
      <span className={styles.first_span2}>
        <Link href="/laser/morpheus8byinmode">{t('Morspanheus8')}</Link>
      </span>
      <span className={styles.first_span3}>
        <Link href="/laser/inmodeforma">{t('Inmode Forma')}</Link>
      </span>
      <span className={styles.first_span4}>
        <Link href="/laser/inmodeminifx">{t('Inmode Mini FX')}</Link>
      </span>
      <span className={styles.first_span5}>
        <Link href="/injection/neuro">{t('Neuromodulator')}</Link>
      </span>
    </div>
  )

import React, { createContext, useMemo, useReducer } from 'react'
import { appWithTranslation } from 'next-i18next'
import { useRouter } from 'next/router'

function App({ Component, pageProps }) {
  const router = useRouter()
  // TODO Refactoring required when languages ​​are added
  const [state, dispatch] = useReducer(reducer, {
    language: router.locale === 'en' ? 'English' : 'Korean'
  });
  
export default appWithTranslation(App)

폴더를 만들어서 json파일에 translation.ko.json, 즉 한국어 json 파일과 translation.en.json, 영어 json 파일을 각각 resources에 맞게 넣어줍니다.

참고: https://record22.tistory.com/107

AS-IS 코드에서는 템플릿과 텍스트가 혼합되어 있어 유지보수성이 떨어지는 문제가 있었습니다. 전역 상태로 언어 설정을 관리하기 위해 createContext와 useReducer를 사용하여 UserContext를 생성했습니다. 각 컴포넌트에서는 useContext를 이용하여 이 UserContext를 활용하여 언어 설정을 가져와 각 링크의 텍스트를 하드코딩하여 출력했습니다. 또한, 언어 디폴트값이 초기에 고정되어 있어 페이지 진입시 언어를 변경하려면 리렌더링이 필요했습니다.

📌고정된 언어 설정: 사용자의 언어 설정이 페이지 진입 시에 디폴트값으로 우선 설정되고, 이후에 사용자가 직접 변경이 필요했습니다. 이는 사용자 경험을 저하시키는 요소였습니다.

📌템플릿과 텍스트의 혼합: 텍스트가 컴포넌트 내부에 하드코딩되어 있어서 템플릿과 번역 텍스트가 혼합되어 있었습니다. 이는 언어의 추가나 번역내용 수정 등의 유지보수를 어렵게 만들었고, 코드의 가독성을 저하시켰습니다.

📌복잡한 조건부 렌더링: 각 링크의 텍스트가 언어에 따라 다르게 표시되도록 하기 위해 삼항연산자가 사용되었습니다. 이는 코드를 복잡하게 만들었고, 가독성을 떨어뜨렸습니다.

📌명시적인 언어 설정의 부재: 코드 내에서 언어 설정이 명시적으로 표현되지 않았습니다. 언어 설정이 각 컴포넌트에서 공유되는 방식이므로 코드를 이해하기 어려웠습니다.

📌재사용성의 한계: 언어 설정 관련 로직이 각 컴포넌트에 중복되어 있어서 코드의 재사용성이 떨어졌습니다. 수정이 필요한 경우 모든 관련 컴포넌트를 수정해야 했습니다.


TO-BE 코드에서는 next-i18next 라이브러리를 도입하여 언어 관리를 개선했습니다.
useTranslation 훅을 사용하여 컴포넌트 내에서 번역 함수를 가져와서 각 링크의 텍스트를 동적으로 출력하도록 변경하였습니다. 또한, 언어 설정은 브라우저의 설정을 기반으로 자동으로 가져오도록 되어 있어, 사용자에게 적절한 디폴트값이 우선 적용되었습니다. 이를 통해 생산성과 사용성이 향상되었습니다.
각 페이지와 언어별 텍스트를 분리하여 JSON 파일로 관리하고, i18next가 언어 분기를 처리하도록 변경했습니다. 이를 통해 언어 추가시 JSON 파일만 추가해주면 되어 효율적으로 언어를 관리할 수 있게 되었습니다.
또한, 템플릿과 텍스트를 분리하여 텍스트는 JSON 파일을 수정함으로써 운영할 수 있게 되었고, 언어 설정은 브라우저의 설정을 가져와 자동으로 변경되도록 구현되었습니다. 이로써 템플릿과 텍스트의 책임 영역이 분리되었고, 유지보수성이 향상되었습니다.

📌다국어 지원 라이브러리 도입: next-i18next 라이브러리를 도입하여 다국어 지원을 향상시켰습니다. 이를 통해 디폴트 언어가 영어로 고정되어 있는 문제를 해결하고, 언어 분기의 책임을 라이브러리에 위임했습니다.

📌템플릿과 텍스트의 분리: 텍스트는 외부 JSON 파일에 저장되어 템플릿과 분리되었습니다. 이로써 유지보수성이 향상되고, 코드의 가독성이 높아졌습니다.

📌조건부 렌더링 간소화: 다국어 지원 라이브러리를 사용하여 각 링크의 텍스트를 동적으로 가져오도록 변경하였습니다. 이로써 조건부 렌더링이 제거되고, 코드가 단순화되었습니다.

📌명시적인 언어 설정: 브라우저의 언어 설정을 가져와 기본 언어를 설정하도록 변경하였습니다. 이를 통해 사용자의 언어 설정을 자동으로 감지하여 언어를 변경할 필요가 없게 되었습니다.

📌로직 분리와 재사용성 향상: 언어 설정 관련 로직을 별도의 파일로 분리하여 중복을 제거하고, 코드의 재사용성을 높였습니다. 이로써 코드 수정이 간편해졌고, 유지보수성이 향상되었습니다.

profile
나를위한 노트필기 📒🔎📝

0개의 댓글