Internationalization of gatsby site using i18next.
포토폴리오 웹사이트를 제작하던 중, 다국어 지원(영어/한국어)기능을 추가하기 위해 i18n 라이브러리를 처음 사용해봤다. 이 방법 이외에도 gatsby에서 지원하는 플러그인을 사용할 수도 있다.
npm install react-i18next i18next --save
npm install i18next-http-backend i18next-browser-languagedetector --save
(if you'd like to detect user language and load translation)Root엥 i18n.js
파일을 생성한다.
// i18n.tsx (root)
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
const languages = ['en', 'ko']; // (*)
i18n
.use(Backend)
.use(LanguageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
debug: true,
whitelist: languages,
interpolation: {
escapeValue: false,
},
});
export default i18n;
SSR방식을 사용하는 웹사이트는 I18nextProvider
로 랩핑을 해줘야 한다. 따라서 Layout 컴포넌트를 I18nextProvider
로 감싸줬다.
// Layout.js
import { I18nextProvider } from 'react-i18next';
import i18n from '../../i18n';
const Layout: React.FC<LayoutProps> = ({ children }) => {
return (
<I18nextProvider i18n={i18n}> // (*)
<div style={{ overflow: 'hidden' }}>
{...}
</div>
</I18nextProvider>
);
};
export default Layout;
Hook을 사용하거나, HOC를 사용하는 방법이 있는데 난 functional component와 함께 Hook을 사용했다. 각자 선호하는 방식을 선택하면 될 것 같다.
유저가 언어를 선택할 수 있는 드롭다운 메뉴를 생성했다. i18next-browser-languagedetector
는 자동으로 사용자의 브라우저의 언어를 인식하여 해당언어로 컨텐츠를 번역한다. 따라서 드롭다운 메뉴의 글자 또한 사용자의 브라우저 언어에 따라서 변경했다.
// Dropdown.js
import { useTranslation } from 'react-i18next';
const LangDropDown: React.FC = () => {
const [lang, setLang] = useState('en');
const { i18n } = useTranslation(); // (*) change the language (118n instace)
const { ref, clickInside, setClickInside } = useClickInside(false);
useEffect(() => {
// Detect user's browser language and change default language of dropdown
const userLanguage: string = window.navigator.language;
if (userLanguage === 'ko') {
setLang('ko');
i18n.changeLanguage('ko');
} else {
setLang('en');
i18n.changeLanguage('en');
}
}, []);
const languages: Languages[] = [
{ lang: 'en', icon: usa },
{ lang: 'ko', icon: korea },
];
const handleClick = (lang: string): void => {
i18n.changeLanguage(lang); // (**)
setLang(lang);
};
return (
<Wrapper>
<span>{lang}</span>
{ isHover && (<Dropdown>
{languages.map((lang) => (
<li onClick={() => handleClick(lang.lang)} key={lang.lang}> // (*)
<img src={lang.icon} alt={lang.lang} />
{lang.lang}
</li>
))}
</Dropdown>)}
<img src={arrow} alt="Language Options" />
</Wrapper>
);
};
export default React.memo(LangDropDown);
번역을 하기 위해서 public - locales - en - translation.json 파일을 생성한다. (언어별로 폴더를 생성한다.)
// locale-en-translation.json
{
"About": {
"0": "Hello",
"1": "I am Suyeon"
}
}
// locale-ko-translation.json
{
"About": {
"0": "안녕하세요",
"1": "저는 수연입니다"
}
}
이제 드디어 번역할 시간이다! 번역을 할 때는 i18next에서 제공하는 t
function을 사용하면 된다.
import { useTranslation } from 'react-i18next';
const About: React.FC = () => {
const { t } = useTranslation(); // (*) Translate
return (
<Wrapper>
<Description>{t('About.0')}</Description> // (*)
<Description>{t('About.1')}</Description>
</Wrapper>
);
};
export default About;
페이지를 이동할 경우, 내가 선택한 언어와 아이콘을 일정하게 보여주기 위해서 gatsby-plugin-layout
을 설치한다.
npm i gatsby-plugin-layout
// gatsby-config.js
plugins: [{
resolve: `gatsby-plugin-layout`,
options: {
component: `${__dirname}/src/components/Layout.js`
}
}]
gatsby build
를 할 때 locales
폴더가 알맞게 public
안에 위치할 수 있도록 경로를 세팅한다.
const fs = require('fs-extra');
const path = require('path');
exports.onPostBuild = () => {
console.log('Copying locales');
fs.copySync(
path.join(__dirname, '/src/locales'),
path.join(__dirname, '/public/locales'),
);
};
참고 자료
step-by-step-guide-to-use-i18next-in-gatsby-app
Multi-language Translate React JS APP with React Hook & I18NEXT
i18next 공식문서
gatsby 공식문서
👍