다국어 POC
- i18n 라이브러리를 최소한으로 설정해서 만들어본 다국어 프로젝트
- 중국 프로젝트를 진행중이라 중국어와 한국어로 다국어 설정
프로젝트 생성 절차
Section titled “프로젝트 생성 절차”-
vite 프로젝트 생성
Terminal window pnpm create vite.../198d62d3ef3-ef8 | +1 +.../198d62d3ef3-ef8 | Progress: resolved 1, reused 0, downloaded 1, added 1, done|o Project name:| poc-i18n|o Select a framework:| React|o Select a variant:| TypeScript + SWC|o Scaffolding project in D:\study\poc-i18n...|— Done. Now run:cd poc-i18npnpm installpnpm run dev -
git 저장소 설정
Terminal window cd poc-i18ngit init
추가 라이브러리 설치
Section titled “추가 라이브러리 설치”-
i18next
Terminal window pnpm install i18next react-i18next -
@types/node
Terminal window pnpm install --save-dev @types/node -
TailwindCSS
Terminal window pnpm install tailwindcss @tailwindcss/vite -
DaisyUI
Terminal window pnpm add -D daisyui@latest -
Prettier
Terminal window pnpm add --save-dev --save-exact prettierpnpm install -D prettier-plugin-tailwindcss -
vite-tsconfig-paths
Terminal window pnpm add -D vite-tsconfig-paths
세부 설정은 각자 편한대로
Section titled “세부 설정은 각자 편한대로”- .prettierrc.cjs
- eslint.config.js
- tsconfig.app.json
- vite.config.ts
- src/index.css
변경/추가된 파일 목록
Section titled “변경/추가된 파일 목록”Directorysrc
Directoryhook
- index.ts
- useLocale.ts
Directorylocales
- i18n.ts
Directoryko
- main_ko.json
Directoryzh
- main_zh.json
Directoryutils
- index.ts
- App.tsx
- main.tsx
{ "apple": "사과", "banana": "바나나", "cherry": "체리"}{ "apple": "苹果", "banana": "香蕉", "cherry": "樱桃"}import i18n from 'i18next'import {initReactI18next} from 'react-i18next'import mainKo from './ko/main_ko.json'import mainZh from './zh/main_zh.json'
const resources = { ko: { translation: mainKo, }, zh: { translation: mainZh, },}
i18n.use(initReactI18next).init({ resources, lng: 'ko', fallbackLng: 'ko', interpolation: { escapeValue: false, },})
export default i18nexport const isNull = <T>(value: T): boolean => value === undefined || value === null
export const createArray = (count: number): number[] => [...Array(count).keys()].map((i) => i)
export const range = (start: number, end: number): number[] => { if (end > start) { return createArray(end - start).map((i) => i + start) } return []}
export const applyParam = (value: string, params?: string[]) => { let buffer = value if (params && params.length > 0) { range(0, params.length).forEach((i) => { const key = `{${i}}` buffer = buffer.replace(key, params[i]) }) } return buffer}import {applyParam, isNull} from '@/utils'import {useTranslation} from 'react-i18next'
export const useLocale = () => { const {i18n, t} = useTranslation()
const getLanguage = () => i18n.language
const changeLanguage = (langCd: string) => { i18n.changeLanguage(langCd) }
const getMessage = (key: string, params: string[]) => { if (isNull(t)) { return '' } const buffer = t(key) return applyParam(buffer, params) }
return { getLanguage, changeLanguage, getMessage, }}export * from './useLocale'import './App.css'import {useLocale} from '@/hook'import {useEffect} from 'react'
const App = () => { const {getMessage, getLanguage, changeLanguage} = useLocale()
useEffect(() => { const language = getLanguage() if (language !== 'ko' && language !== 'zh') { changeLanguage('zh') } }, [])
return ( <div className="flex h-screen w-screen flex-col bg-white"> <div className="m-2"> <button className="btn btn-primary mr-3" onClick={() => changeLanguage('ko')}> 한국어 </button> <button className="btn btn-primary mr-3" onClick={() => changeLanguage('zh')}> 중국어 </button> </div> <div> <div className="text-black">{getMessage('apple', [])}</div> <div className="text-black">{getMessage('banana', [])}</div> <div className="text-black">{getMessage('cherry', [])}</div> </div> </div> )}
export default Appimport {StrictMode} from 'react'import {createRoot} from 'react-dom/client'import './index.css'import App from './App.tsx'import {I18nextProvider} from 'react-i18next'import i18n from './locales/i18n.ts'
createRoot(document.getElementById('root')!).render( <StrictMode> <I18nextProvider i18n={i18n}> <App /> </I18nextProvider> </StrictMode>,)- 버튼을 클릭하면 언어가 변경된다.
