신규 프로젝트의 다국어 적용을 마치고
기존 프로젝트에도 다국어 적용이 필요한 상황이었습니다.
하지만 문제는 기존 프로젝트는 자바스크립트 프로젝트라는 것입니다.
신규 프로젝트는 타입스크립트로 진행했기 때문에
어려움 없이 자동완성의 혜택을 누릴 수 있었지만,
자바스크립트 프로젝트에서는 다국어 메시지 자동완성이 불가능했습니다.
자동완성 없이 다국어 메시지를 적용한다고? 🤔
이건 여러모로 좋지 않을 것 같아서
방법을 찾아봤습니다.
결론부터 말하면 부분적 타입스크립트 도입 + JSDoc을 활용해서
다국어 메시지의 자동완성을 구현했던 건에 대해서 소개하겠습니다. 😀
📝 JavaScript 프로젝트에서 .d.ts 파일 생성하기
⦁1. 타입스크립트를 devDependencies로 설치
yarn add -D typescript
.d.ts 파일을 생성하기 위해선 타입스크립트를 설치해야 합니다.
-D는 --dev의 줄임말로, 개발에만 필요한 패키지를 설치할 때 사용합니다.
typescript는 우리가 작성한 JS 코드에 타입 자동완성을 위한 도구일 뿐, 실제 빌드나 배포에는 포함되지 않습니다.
⦁2. .d.ts 파일이란?
- 코드의 구현 없이 타입만 정의되어 있습니다.
- JS 파일에서도 사용할 수 있어, 자동완성과 타입 체크를 가능하게 해줍니다.
- 특히 다국어 JSON 메시지 같은 구조화된 데이터를 다룰 때, 키 자동완성에 매우 유용합니다.
.d.ts 파일은 타입스크립트의 타입 선언 파일(declaration file) 입니다.
저희는 i18n.d.ts 파일을 생성해서, 다국어 메시지 자동완성을 구현할 거예요
JS 프로젝트에서 프로젝트 전체를 TS로 마이그레이션 하지 않아도 부분적으로 타입의 혜택을 누릴 수 있습니다.
⦁3. jsconfig는 그대로 유지하세요!
타입스크립트를 설치했다고 해서, jsconfig.json을 tsconfig.json으로 변경할 필요는 없습니다.
오히려 JS 기반 프로젝트라면 tsconfig.json으로 전환하면 에러가 너무 많이 생기고, 설정의 충돌이 발생할 수 있습니다.
따라서 jsconfig를 유지한 채 타입 보강만 하는 것을 추천드립니다.
// jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
},
"checkJs": true, // 이거랑
"resolveJsonModule": true // 이거만 추가해주세요
},
"include": ["src"]
}
2가지 옵션 정도는 추가해 주셔야 합니다.
- checkJs : JSDoc 사용하기 위함
- resolveJsonModule : JSON 파일을 import 하기 위해 필요 (다국어 메시지는 JSON이니까요)
📝 필요한 파일 생성
✅ next-intl을 세팅했다면 위와 같이 i18n 폴더에 파일들이 있을 겁니다.
** 3월 12일에 @4버전으로 올라가면서 라우팅 관련 래핑 컴포넌트를 export 하는 곳이
navigation으로 분리되었습니다. 참고하세요 !
⦁1. i18n.d.ts
// i18n.d.ts
import en from '../../messages/en.json';
type Messages = typeof en;
/* 중첩 객체 자동 완성을 위한 코드 */
type NestedKeyOf<T> = {
[K in keyof T & string]: T[K] extends object
? `${K}.${NestedKeyOf<T[K]>}`
: K;
}[keyof T & string];
declare global {
type TKey = NestedKeyOf<Messages>;
}
타입스크립트 프로젝트에서는, 메시지의 typeof만 넘겼을 때에도 정상적으로 자동완성이 되었지만,
자바스크립트 프로젝트에서는 NestedKeyOf 처럼 타입을 만들어줘야 자동완성을 사용할 수 있더라고요.
⦁2. useT() 커스텀 훅 생성
/**
* @typedef {import('./i18n').TKey} TKey
*/
import { useTranslations } from 'next-intl';
/**
* @returns {(key: TKey) => string}
*/
export function useT() {
const t = useTranslations();
/**
* @param {TKey} key
*/
return function (key) {
return t(key);
};
}
useTranslations을 래핑한 커스텀 훅을 생성합니다.
JSDoc를 사용해서 JS에서도 타입 추론과 자동 완성을 제공합니다! 😎
⦁3. 사용해보기
import { useT } from '@/i18n/useT';
function Home() {
const t = useT();
...
{t('Common.action')}
JS 프로젝트에서 다국어 메시지 자동완성 구현하기 끝 ! 🥳
+ 4/15 추가
JSDoc을 사용해 타입을 정의했을 때, 타입 추론 속도가 느린지 자동완성이 불안정한 문제가 발생했습니다. 🥲
결국 useT() 훅을 JSDoc 대신 TypeScript로 전환하여 문제를 해결했습니다.
JSDoc 써보고 싶었는데 아쉽네요
// 1. i18n.d.ts 파일 제거
// 2. useT.js -> useT.ts 타입스크립트로 변환 및 타입 직접 사용
// useT.ts
import { useTranslations } from 'next-intl';
import en from '../../messages/en.json';
/* 다국어 메세지 타입 정의 */
type Messages = typeof en;
type NestedKeyOf<T> = {
[K in keyof T & string]: T[K] extends object
? `${K}.${NestedKeyOf<T[K]>}`
: K;
}[keyof T & string];
type TKey = NestedKeyOf<Messages>;
/* useTranslations 래핑 커스텀 훅 */
export function useT() {
const t = useTranslations();
return (key: TKey): string => t(key);
}
📝 마치면서
프로젝트 전체를 타입스크립트로 마이그레이션할 수 있으면
좋겠지만, 현실적으로 쉽지 않은 상황이 있을 수 있습니다.
사내 신규 프로젝트에 타입스크립트를 도입하길 정말 다행인 것 같습니다.
이럴 땐 이 방법처럼 부분적으로만
타입스크립트를 적용하는 것도 좋은 방법인 것 같습니다. 😀
참고 문헌 :
'Front-End > Next' 카테고리의 다른 글
[Next.js] 구글 스프레드시트로 i18n 메시지 관리하기 (Apps Script json 추출) (0) | 2025.03.13 |
---|---|
[Next.js] Next 15 국제화라이브러리 비교 + 적용하기 (i18n, next-intl) (2) | 2025.02.24 |
[Next.js] 넥스트 빌드파일 html id="__next_error__" 해결방법 (useSearchParams) (0) | 2025.01.21 |
[Next.js] TypeError: jsxDEV is not a function 해결 방법 (캐시 에러) (3) | 2024.10.07 |