1. generateTranslation.js 파일에 csv 정보 추가

// scripts/generateTranslations.js
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import fs from 'fs';
import csv from 'csv-parser';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

// 번역 csv 파일 배열에 추가
// locales: 파일명, translations: 번역 스크립트를 작성할 csv 파일명
const csvs = [
  { locales: 'common.json', translations: 'commonTranslations.csv' },
  { locales: 'mainPage.json', translations: 'mainPageTranslations.csv' },
];

// CSV 파일 경로 및 출력 디렉터리 설정
const csvFilePaths = csvs.map(csv => ({
  locales: csv.locales,
  translations: join(__dirname, '..', 'translations', csv.translations),
}));
const localesPath = join(__dirname, '..', 'locales');

// CSV 파일을 스트림으로 읽고, 각 행(row)을 처리
csvFilePaths.forEach(csvFilePath => {
  // 언어별 번역 데이터를 담을 객체
  const translations = {};
  fs.createReadStream(csvFilePath.translations)
    .pipe(csv())
    .on('data', row => {
      const translationKey = row.key;
      for (const lang in row) {
        if (lang === 'key') continue;
        if (!translations[lang]) {
          translations[lang] = {};
        }
        translations[lang][translationKey] = row[lang];
      }
    })
    .on('end', () => {
      console.log('CSV 파일 읽기 완료!');

      // 언어별로 json 파일 생성
      for (const lang of Object.keys(translations)) {
        const langDir = join(localesPath, lang);
        if (!fs.existsSync(langDir)) {
          fs.mkdirSync(langDir, { recursive: true });
        }
        const jsonFilePath = join(langDir, csvFilePath.locales);
        fs.writeFileSync(
          jsonFilePath,
          JSON.stringify(translations[lang], null, 2),
          'utf8',
        );
        console.log(`${lang} -> ${jsonFilePath} 생성 완료`);
      }
    });
});

2. csv 파일 작성 (ex: translations/commonTranslations.csv 파일)

key,ko,en
signUp,회원가입,Sign up
login,로그인,Login
searchRecruitment,채용 공고 검색하기,Search for job postings
recruitmentInfo,채용정보,recruitment
companiesInfo,기업정보,Companies
nearBy,주변기업찾기,Surrounding
community,커뮤니티,Community

2-1(Optional). 커밋 푸시 없이 json을 생성하고 싶은 경우

터미널에 아래 명령어를 실행

pnpm exec ts-node --transpile-only scripts/generateTranslations.js

3. 번역 기능 적용

  1. i18n/i18n.ts 파일에 json 정보 추가
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

// json 파일 import
import enCommon from '../locales/en/common.json';
import enMainPage from '../locales/en/mainPage.json';
import koCommon from '../locales/ko/common.json';
import koMainPage from '../locales/ko/mainPage.json';

// resources에 추가
const resources = {
  en: {
    common: enCommon,
    mainPage: enMainPage,
  },
  ko: {
    common: koCommon,
    mainPage: koMainPage,
  },
};

i18n.use(initReactI18next).init({
  resources,
  lng: 'ko',
  fallbackLng: 'en',
  // ns에 파일명 추가
  ns: ['common', 'mainPage'],
  defaultNS: 'common',
  interpolation: {
    escapeValue: false,
  },
});

export default i18n;

  1. useTranslation 훅 사용
import { useTranslation } from 'react-i18next';
import styles from './searchSection.module.scss';
import SearchSectionForm from './SearchSectionForm';

export default function SearchSection() {
	// useTranslation 인자에 번역 텍스트를 제공할 파일명 입력(i18n 리소스에 기입한 key를 입력)
  const { t } = useTranslation('mainPage');

  return (
    <section className={styles.searchSection}>
      <div className={styles.container}>
        <div className={styles.searchWrapper}>
          <div className={styles.searchHeader}>
	          {/* csv 파일내에 작성한 key값 입력 */}
            <h2 className={styles.sectionTitle}>{t('searchTitle')}</h2>
            <p className={styles.sectionSubtitle}>{t('searchSubTitle')}</p>
            <SearchSectionForm />
          </div>
        </div>
      </div>
    </section>
  );
}