33. 다국어 지원 (i18n) + 에러 해결

random-olive·2023년 3월 26일
0
  • 다국어지원을 하기 위해 i18n을 적용했다.

1. 설치

npm i i18next react-i18next @types/i18next @types/react-i18next

2. 설정

3. menuText 내용 i18n.json으로 옮기기

//locales/en/main.json
{
  "test": "Helo",
  "mainMenu": [
    {
      "title": "main",
      "href": "/home",
      "list": [
        { "title": "🐰", "href": "/housework" },
        { "title": "♥️🐇", "href": "/wandb" },
        { "title": "recipe", "href": "/address" },
        { "title": "hobby", "href": "/address" },
        { "title": "party", "href": "/address" },
        { "title": "travel", "href": "/address" },
        { "title": "community", "href": "/address" },
        { "title": "store", "href": "/address" }
      ]
    }
  ]
}
  • menuText로 지정했던 메뉴 이름들을 다국어지원이 가능하게 옮기려고 한다.
//Layouts.tsx
export const MenuBar = ({ selected, setSelected }: BarProp) => {
  return (
    <>
      {mainMenu[0].list.map((el, idx) => (
  	    <<Main key={idx} idx={idx}>
          ...
        </Main>
      ))} 
    </>
  );
};

//Layouts.tsx
import { useTranslation } from 'react-i18next';

export const MenuBar = ({ selected, setSelected }: BarProp) => {
  const {t} = useTranslation();
  return (
    <>
      {t('main:mainMenu')[0].list.map((el, idx) => (
  	    <Main key={idx} idx={idx}>
          ...
        </Main>
      ))} 
    </>
  );
};

단순히 바꿔서 써보았더니
🟥 Property 'list' does not exist on type 'string'이라는 에러가 나온다: t('main:mainMenu') 부분이 string으로 나타나서 사용할 수 없다는 것 같아 해당 값을 화면에 출력해보니

🟥 값은 key 'mainMenu (ko-KR)' returned an object instead of string.이라 나오고,
콘솔로그에는 accessing an object 라는 메세지가 나온다.
공식문서를 참조 후, 다음과 같이 옵션을 추가했다.

t('main:mainMenu',{ returnObjects: true })

이번에는 콘솔로그에는 정상적으로 object가 찍히는데 화면에서 출력하려고 했을 때는 다음과 같은 에러가 발생했다.
🟥 Objects are not valid as a React child ...

{JSON.stringify(t('main:mainMenu', { returnObjects: true }))}

객체를 stringify해서 렌더링하니까 성공적으로 출력되었다.
하지만 string이라서 그 다음 코드(객체의 map 활용)를 제대로 활용할 수 없어서, object로 출력하는 JSON.parse()를 사용했다.

{JSON.parse(JSON.stringify(t('main:mainMenu', { returnObjects: true })))}
  • 즉, JSON을 객체로 온전히 활용하려면 우선 JSON.stringify로 string화 시켜준 후, 다시 객체로 변형하는 JSON.parse 순으로 진행하면 된다.

  • stringify하지 않고 바로 JSON.parse만 한다면
    🟥 Uncaught SyntaxError: "[object Object]" is not valid JSON
    콘솔로그 에러를 볼 수 있다.

  • stringify하고 JSON.parse를 하지 않고 객체 활용을 한다면
    또다시 🟥 Property 'list' does not exist on type 'string'. 에러를 만난다.

  • 결과적으로 다음과 같이 파싱 후, 변수로 바꿔치기해서 기존 결과를 유지하게 되었다.

//MenuBar.tsx
import { useTranslation } from 'react-i18next';

export const MenuBar = ({ selected, setSelected }: BarProp) => {
  const { t } = useTranslation();
  const objectParsed = JSON.parse(
    JSON.stringify(t('main:mainMenu', { returnObjects: true }))
  );

  return (
    <>
      <Horizontal margin={DEFAULT.MENU_MARGIN}>
        {objectParsed.list.map((el: any, idx: number) => (
          <Main key={idx} idx={idx}>
            {el.title}
            ... (기존 코드)
          </Main>
        ))}
      </Horizontal>
    </>
  );
};

text.ts -> i18n.json 으로 변환하며 느낀 점

  • 기존 문제가 모두 해결된 후에 해당 변환을 진행하는 게 편하다.
  • 메뉴 타입 지정에 에러가 있었다: 필요하지 않은 메뉴(x 항목)가 메뉴에 들어가게 되었는데, 이를 삭제하면 타입 에러가 발생했다.
  • json 파일로 변환 후에는 언어 개수에 따라 해당 자료를 지우거나 추가했어야 하므로, 해당 문제를 해결하기 위해 기존의 ts 파일을 남겨둔 채, 해결 후 ts 파일을 지우기로 했다.

🟥 콘솔에러 : i18next::translator: missingKey en-US basic cycle cycle

//발생 코드
const cycleMenu = JSON.parse(
    JSON.stringify(t('basic:cycle', { returnObjects: true }))
  );
  • en-US 모드일 때 basic.json에서 해당 key (basic)을 찾을 수 없다고 나오는 에러

  • 파일 이름을 item.json으로 변경한 것이 원인이었다: translation할 파일 이름이 없거나, 그에 맞는 key 값이 없으면 같은 에러를 발생시킨다.

  • 코드를 다음과 같이 수정하니까 잘 되었다.
    //발생 코드
    const cycleMenu = JSON.parse(
    JSON.stringify(t('item:cycle', { returnObjects: true }))
    );




profile
Doubts kills more dreams than failure ever will

0개의 댓글