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} 생성 완료`);
}
});
});
translations/commonTranslations.csv 파일)key,ko,en
signUp,회원가입,Sign up
login,로그인,Login
searchRecruitment,채용 공고 검색하기,Search for job postings
recruitmentInfo,채용정보,recruitment
companiesInfo,기업정보,Companies
nearBy,주변기업찾기,Surrounding
community,커뮤니티,Community
터미널에 아래 명령어를 실행
pnpm exec ts-node --transpile-only scripts/generateTranslations.js
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;
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>
);
}