0. 계기

기존 프로젝트에서 다중 언어(3개 이상)를 제공하고 있었는데,
단순히 json 만 parsing하는 방식을 사용해서 언어 관리가 쉽지 않았다
(미번역 단어를 찾기나, 언어별로 missing key를 찾는 등의 일이 어려웠다.)
이에 i18n Ally와 같은 extension을 사용해 언어를 관리하고자 멀고도 험난한 여정을 거친 적용기다.

교훈: 처음 전략을 잘 세우자 (프로젝트 덩치가 조금 커서 거의 2주일을 소모했다.)

 

기존 json 정리 -> i18n 도입(초기 설정 -> i18n Ally -> 파일에 적용)의 순서를 거쳤다.

1. 기존 json 정리 (일주일+ 소모)

  • 기존 json이 약 7개 이상의 파일로 구성되어있었기에 이를 하나로 합체하였다.
  • 화이트라벨링 관련 표현도 따로 파일이 존재했는데, 이것은 i18n의 별도 네임스페이스로 두기 위해 남겼다.
  • 중복 표현&key를 제거하며 일부 정리를 거쳤다.
  • 다른 검토가 필요한 표현은 타 부서와의 협의를 위해 우선 두었다.

2. i18n 도입 (일주일 소모)

  • 초기 설정
    • 패키지 설치
    • 루트 또는 /src에 i18n.ts 파일을 만든다.
yarn add i18next i18next i18next-browser-languagedetector i18next-http-backend
import i18n from 'i18next';
import LanguageDetector from 'i18next-browser-languagedetector';
import Backend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';

// i18n 초기 설정
i18n
  .use(Backend) // 서버에서 언어 파일을 가져오는 기능
  .use(LanguageDetector) // 사용자의 브라우저 언어를 감지하는 기능
  .use(initReactI18next) // react-i18next 연결
  .init({
    fallbackLng: 'en', // 기본 언어 설정
    returnEmptyString: false, // json에서 value가 "" 형태인 항목도 fallback 처리하도록 하는 플래그
    debug: true, // 개발 중 디버그 모드 활성화
    interpolation: {
      escapeValue: false, // 리액트는 기본적으로 XSS 공격을 방지하므로 별도 이스케이프가 필요 없음
    },
    ns: [**Your Namespaces**],
    defaultNS: '**Your Default Namespace**',
    backend: {
      loadPath: '**Your Path of Locale Files**/{{lng}}/{{ns}}.json', // 언어 리소스 파일 경로
    },
  });

export default i18n;

 

  • i18n Ally 설정
    • extension을 위해, `.vscode/settings.json` 에 아래와 같이 설정해준다.
"i18n-ally.localesPaths": ["Your Path of Locale Files"],
"i18n-ally.enabledFrameworks": ["react-i18next"],
"i18n-ally.keystyle": "nested"
// if using namespace...
"i18n-ally.defaultNamespace": "Your Default Namespace",
"i18n-ally.namespace": true,

 

  • 실제 사용: 함수형 컴포넌트
    • useTranslation hook을 사용하여 함수형 컴포넌트 내부에서 아래와 같이 사용할 수 있다.
import { useTranslation } from 'react-i18next';

...
// default namespace만 사용할 경우
const { t, i18n } = useTranslation();
// namespace를 더 사용할 경우
const { t, i18n } = useTranslation([a, b, ...]);

console.log(t('test')) // default namespace는 생략 가능
console.log(t('a:test'))
console.log(i18n.language) // 현재 사용중인 언어
...

 

  • 실제 사용: 파일
    • 아래처럼 그냥 import해서 쓸 수도 있다. (권장하진 않는다.)
import { t } from 'i18next';
import i18n from 'src/i18n';
import type { WithTranslation } from 'react-i18next';
import { withTranslation } from 'react-i18next';

class Test extends React.PureComponent<PropsType & WithTranslation, StateTypes> {
	constructor(props: PropsType & WithTranslation) {
    	super(props);
    	...

    render() {
        const { t } = this.props;
        return <p>{t('test')}</p>;
	}
 }

export default withTranslation()(Test);

// 뭔가로 이미 감싸고 있었다면
export default connect(...)(withTranslation()(Test));

// forwardRef를 써야한다면
const TestWithRef = React.forwardRef((props: WithTranslation, ref: React.Ref<Test>) => {
  return <Test {...props} ref={ref} />;
});

export default withTranslation()(TestWithRef);

3. 결론

  • 언어 설정은 초반에 잘하자.
  • 화이트라벨링을 더 잘 적용할 수 있는 방법이 있으면 좋겠다.
  • namespace를 좀더 명확하게 가져올 수 있는 방식이 있었으면 좋겠다. : 으로 구분하는 방식이 보기 어려운 것 같다.(어처피 ally 쓸거지만)

 

다음은 이렇게 변환한 i18n json을 가지고 구글 스프레드시트에 연동하는 tool을 만든 후기를 작성하겠다.

 

** 여담

Uncaught Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.  에러가 발생한다면

<Suspense> 로 감싸져있는지 확인하자.

이유는 여기 블로그에 잘 나와있다.

https://velog.io/@leejungho9/Error-A-component-suspended-while-responding-to-synchronous-input.-This-will-cause-the-UI-to-be-replaced-with-a-loading-indicator.-To-fix-updates-that-suspend-should-be-wrapped-with-startTransition

 

[Error] A component suspended while responding to synchronous input.

최근 리액트로 프로젝트를 진행하다 다음과 같은 에러를 마주했다. A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading

velog.io

 

** 여담2

locale 파일을 public에 넣지 않으면 실제 서비스 할 때 정보를 못 불러오는 문제가 있었다.

원인은 아직 파악 못했지만 public에 넣어야 하는 듯 하다.

'[Frontend] > React, TS, JS' 카테고리의 다른 글

[node.js] Google Spreadsheet API 사용기  (3) 2024.10.25

+ Recent posts