๐Ÿ‘ฉ‍๐Ÿ’ป/React

[React.js๋กœ ๋งŒ๋“œ๋Š” Tech Blog] #5 ์–ธ์–ด ์„ค์ •์„ ์œ„ํ•œ react-i18next ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•˜๊ธฐ/๊ตญ์ œํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(i18n)

ํ•œ๋‚˜ 2021. 2. 26. 18:54

2021/02/21 - [๐Ÿ‘ฉ‍๐Ÿ’ป/React.js] - [React.js๋กœ ๋งŒ๋“œ๋Š” Tech Blog] #4 Window.scrollY/window.pageYOffset

2021/02/16 - [๐Ÿ‘ฉ‍๐Ÿ’ป/React.js] - [React.js๋กœ ๋งŒ๋“œ๋Š” Tech Blog] #3 master ๋ธŒ๋žœ์น˜๋กœ ํ†ตํ•ฉํ•˜๊ธฐ/github pages์— ์žฌ๋ฐฐํฌํ•˜๊ธฐ

2021/02/13 - [๐Ÿ‘ฉ‍๐Ÿ’ป/React.js] - [React.js๋กœ ๋งŒ๋“œ๋Š” Tech Blog] #2 react router ๋„ค๋น„๊ฒŒ์ด์…˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ™œ์šฉ

2021/02/09 - [๐Ÿ‘ฉ‍๐Ÿ’ป/React.js] - [React.js๋กœ ๋งŒ๋“œ๋Š” Tech Blog] #1 Figma ํ”„๋กœํ† ํƒ€์ดํ•‘/๊ฐœ๋ฐœํ™˜๊ฒฝ ์„ธํŒ…/Grommet UI Library/useState/Responsive Header ๋งŒ๋“ค๊ธฐ


๋ธ”๋กœ๊ทธ์˜ ๊ธฐ๋ณธ ์ปจํ…์ธ ๋Š” ์˜์–ด๋กœ ์ž‘์„ฑํ–ˆ๋‹ค. ์ด๋ ฅ์„œ ๊ฐ™์ด ์ž๊ธฐ PR๋ฅผ ํ•ด์•ผ ํ•˜๋Š” ๊ธ€์„ ์“ธ ๋•Œ๋Š” ์˜์–ด๊ฐ€ ๋‚˜์•„์„œ ๊ทธ๋Œ€๋กœ ๋‘์—ˆ์ง€๋งŒ, ์„œ์šธ์—์„œ ๊ตฌ์งํ™œ๋™์„ ํ•  ๊ฒƒ์ธ๋ฐ ์˜์–ด๋กœ๋งŒ ๋‘๋Š” ๊ฒƒ๋„ ์•„๋‹ˆ๋‹ค ์‹ถ์–ด ์ƒ๊ฐ๋‚œ ๊น€์— ์–ด์ œ ์–ธ์–ด ์„ค์ • ๊ธฐ๋Šฅ์„ ๋„ฃ์–ด๋‘์—ˆ๋‹ค.

๊ตญ์ œํ™”(i18n) ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ž€

Internationalization์˜ ๋งจ ์•ž์ž, ๋งจ ๋์ž๋ฅผ ๋”ด ์šฉ์–ด์ด๋‹ค. i18next๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ตญ์ œํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค. ์ด๋ฒˆ์—๋Š” react-i18next ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

์–ธ์–ด ์„ ํƒ UI ๋งŒ๋“ค๊ธฐ

๋ฉ”์ธ ๋ฉ”๋‰ด์™€ ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด ๋‘ ๊ตฐ๋ฐ์— ์–ธ์–ด ์„ค์ •์„ ์œ„ํ•ด Grommet์—์„œ ์ œ๊ณตํ•˜๋Š” ์…€๋ ‰ํŠธ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. Nav ์ปดํฌ๋„ŒํŠธ ์•ˆ์— ์œ„์น˜์‹œํ‚ค๊ธฐ์—” ๋„ˆ๋ฌด ๋ณต์žกํ•  ๊ฒƒ ๊ฐ™์•„์„œ ์ผ๋‹จ์€ ์ด๋ ‡๊ฒŒ ํ•ด๋‘์—ˆ๋Š”๋ฐ, Collapsableํ•œ side menu์—์„œ์˜ ์…€๋ ‰ํŠธ ์œ„์น˜๋Š” ์ข‹์€๋ฐ ๋ฉ”์ธ ํฌ์ŠคํŠธ ์ƒ๋‹จ์— ์œ„์น˜ํ•˜๋„๋ก ํ•œ ๊ฑด ์˜ ๋งˆ์Œ์— ์•ˆ ๋“ค์–ด์„œ dark mode๋ผ๋“ ์ง€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์ด ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๋ฉด ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ณ„๋„์˜ ์‚ฌ์ด๋“œ ๋ฉ”๋‰ด๋ฅผ ๋˜ ๊พธ๋ฆฌ๋Š” ๊ฒŒ ๋‚˜์•„๋ณด์ธ๋‹ค.

 

์–ด์จŒ๋“  ์–ธ์–ด ์„ค์ •์„ ์œ„ํ•œ UI๋ฅผ ๋งŒ๋“ ๋‹ค. Github ํ’€ ์†Œ์Šค ์ฝ”๋“œ๋Š” ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

Github ์ฝ”๋“œ

 

hannah26hannah/hannah26hannah.github.io

๐ŸŽฏ Dev Blog + Portfolio . Contribute to hannah26hannah/hannah26hannah.github.io development by creating an account on GitHub.

github.com

 

 

์…€๋ ‰ํŠธ ์ปดํฌ๋„ŒํŠธ๋Š” options ์†์„ฑ์„ ๊ฐ€์ง„๋‹ค. options ๋ฐฐ์—ด์„ ์„ ์–ธํ•ด label๊ณผ value ํ‚ค๋ฅผ ๊ฐ€์ง€๋„๋ก ํ–ˆ๋‹ค. ๊ฐ๊ฐ์€ labelKey์™€ valueKey ์†์„ฑ์œผ๋กœ ๊ตฌ๋ถ„์ง€์–ด์ค€๋‹ค. ์ œ๊ณต๋˜๋Š” onChange ์†์„ฑ์€ options์˜ option์— forEach์ฒ˜๋Ÿผ ๊ฐ ์ด๋ฒคํŠธ๋ฅผ ๊ฑธ ์ˆ˜ ์žˆ๋„๋ก ๋˜์–ด ์žˆ๋‹ค. changeLang ํ•จ์ˆ˜๋ฅผ ์จ์„œ ์„ ํƒ๋œ option์œผ๋กœ ์–ธ์–ด๋ฅผ ์„ค์ •ํ•œ๋‹ค. i18next๊ฐ€ ์ œ๊ณตํ•˜๋Š” changeLanguage ๋ฉ”์„œ๋“œ๋ฅผ ์“ฐ๋ฉด ๋œ๋‹ค. ko, en ๊ฐ™์€ ๋ฌธ์ž์—ด์„ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

 

ํ•„์š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‹ค์šด๋กœ๋“œ ๋ฐ ์„ค์ •

๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๊ฒ€ํ† ํ•ด๋ณด๋‹ค๊ฐ€, ์ด ๋ธ”๋กœ๊ทธ ๊ธ€๊ณผ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด react-i18next ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ ํƒํ–ˆ๋‹ค.

 

yarn add react-i18next
// or
npm install react-i18next --save

 

yarn์„ ํ†ตํ•ด ๋‹ค์šด ๋ฐ›์•„์ค€ ํ›„, src ์•„๋ž˜์— config๋ผ๋Š” ํด๋”๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ–ˆ๋‹ค.

 

์„ค์ •์„ ์œ„ํ•œ i18n.js ํŒŒ์ผ, ๋ฒˆ์—ญ ์–ธ์–ด ๊ฐ’์„ ๋ชจ์•„๋‘” json ํŒŒ์ผ์„ ๊ฐ๊ฐ ๋งŒ๋“ค์–ด์ค€๋‹ค.

 

 

i18n์„ import ํ•ด์ฃผ๊ณ , initReactI18next๋กœ import ํ•ด์ค€๋‹ค. ๋งŒ๋“ค์–ด๋‘” json ํŒŒ์ผ๋“ค์„ ๊ฐ๊ฐ ๊ฐ€์ง€๊ณ  ์˜ค๊ณ , resource ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด ์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์ž‘์„ฑํ•ด์ค€๋‹ค. debug๋ฅผ true ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด๋‘๋ฉด ๊ฐœ๋ฐœ ์‹œ์— ๋ฒˆ์—ญ ๊ฐ’์ด ์—†๊ฑฐ๋‚˜ ๋ฒˆ์—ญ์–ด๋ฅผ ๋ฐ”๊ฟ€ ๋•Œ update๋˜๋Š” ๋‚ด์šฉ์„ ์ฝ˜์†”์— ์ฐ์–ด์ค€๋‹ค. ๊ธฐ๋ณธ ์–ธ์–ด๋Š” 'en'๋กœ ํ•ด์ฃผ์—ˆ๋‹ค. (

i18next-browser-languagedetector์— ๋Œ€ํ•œ ๋‚ด์šฉ์€ ๋งจ ์•„๋ž˜ ๋ชฉ์ฐจ๋ฅผ ์ฐธ๊ณ )

 

์ด์ œ index.js๋กœ ์™€์„œ, ์„ค์ • ํŒŒ์ผ์„ import './config/lang/i18n' ๋กœ ๊ฐ€์ ธ์™€์ค€๋‹ค.

 

i18next ์‚ฌ์šฉํ•˜๊ธฐ

 

๊ณต์‹ ํ™ˆํŽ˜์ด์ง€์— ์„ค๋ช…์ด ์ž˜ ๋˜์–ด ์žˆ๋Š”๋ฐ, ๊ฒฝ์šฐ์— ๋”ฐ๋ผ ํ•„์š”ํ•œ ๋ฐฉ๋ฒ•์„ ์ทจํ•˜๋ฉด ๋œ๋‹ค. useTranslation Hook์„ ์“ฐ๊ฑฐ๋‚˜, withTranslation HOC์„ ์“ฐ๊ฑฐ๋‚˜, Trans ์ปดํฌ๋„ŒํŠธ๋ฅผ ์“ฐ๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

 

withTranslation Hoc

์šฐ์„  header์ธ App Bar์˜ ๋ฉ”๋‰ด ์ด๋ฆ„๋“ค์„ ๋ฒˆ์—ญํ•ด๋ณด์•˜๋‹ค.

 

t๋Š” ๋ฒˆ์—ญํ•˜๊ณ ์ž ํ•˜๋Š” ์–ธ์–ด๋ฅผ ์ธ์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค. string ํƒ€์ž…์œผ๋กœ ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ Contact๋Š” json ํŒŒ์ผ์— ์ผ๋˜ Key๊ฐ€ ๋œ๋‹ค.

translation.en.json
translation.ko.json

๋‹จ์ˆœํžˆ 1:1๋กœ ๋งค์นญ๋˜๋Š” ํ…์ŠคํŠธ๋ผ๋ฉด ์ด ๋ฐฉ๋ฒ•์œผ๋กœ ์ถฉ๋ถ„ํ•œ๋ฐ, ๊ธด ๊ธ€์— ๋Œ€ํ•ด์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ• ๊นŒ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ key๋ฅผ ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ํ™œ์šฉํ•˜๊ณ  Trans ์ปดํฌ๋„ŒํŠธ๋ฅผ ์“ฐ๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

Trans Component

ํ™ˆํŽ˜์ด์ง€์˜ ๋žœ๋”ฉ ํŽ˜์ด์ง€์— ํฌํŠธํด๋ฆฌ์˜ค์™€ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ์˜ ์ •๋ณด๋ฅผ ๋‹ด์€, ๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์•„๋‹Œ js ํŒŒ์ผ์ด ์žˆ๋‹ค.

 

contents๋Š” ๊ฐ์ฒด๋ฅผ ์›์†Œ๋กœ ํ•œ ๋ฐฐ์—ด์ด๊ณ , titleComponent๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ’์œผ๋กœ ๊ฐ€์ง€๊ณ , contents๋Š” ์›๋ž˜ ๊ธด ๊ธ€์˜ string์„ ๊ฐ–๊ณ  ์žˆ์—ˆ๋‹ค. contents_ko ๋ผ๋Š” ํ‚ค๋ฅผ ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•ด ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ ๊ฐ’์„ ๊ฐ€์ง€๋ ค๊ณ  ํ–ˆ์ง€๋งŒ, ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง์ด ์•ˆ ๋˜๊ธธ๋ž˜ ์ด ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋‘ Trans ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ•ด ์ฒ˜๋ฆฌํ–ˆ๋‹ค. json ํŒŒ์ผ์— ์ผ๋˜ ํ‚ค ๊ฐ’์„ Trans ์ปดํฌ๋„ŒํŠธ ์‚ฌ์ด์— ์œ„์น˜์‹œํ‚ค๋ฉด ๋œ๋‹ค. 

 

์ฐธ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” HTML ํƒœ๊ทธ๋„ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

 

์„ค์ • ์–ธ์–ด๋ฅผ ๊ธฐ์–ตํ•˜๊ธฐ w/i18next-browser-languagedetector

๋งˆ์ง€๋ง‰์œผ๋กœ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•ด ์‚ฌ์šฉ์ž์˜ ์–ธ์–ด ์„ค์ •์„ ๊ธฐ์–ตํ•˜๊ฒŒ ํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ์œ„ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•œ๋‹ค.

yarn add i18next-browser-languagedetector

๊ณต์‹ ๋ฌธ์„œ์˜ instance ๋ถ€๋ถ„์„ ์ฐธ๊ณ ํ•ด์„œ, i18n.js ์„ค์ • ํŒŒ์ผ์„ ์ž‘์„ฑํ•ด์ฃผ๋ฉด ๋œ๋‹ค. i18n์„ init ํ•˜๊ธฐ ์ „ language Detector๋ฅผ useํ•˜๊ณ , ๊ธฐ๋ณธ ์–ธ์–ด ์„ค์ • ์†์„ฑ์ธ lang: 'en'์„ ์ฃผ์„์ฒ˜๋ฆฌํ•œ๋‹ค.

 

์ด์ œ ์–ธ์–ด๋ฅผ ์„ค์ •ํ•˜๋ฉด i19nextLng์ด๋ผ๋Š” ํ‚ค๋กœ ์–ธ์–ด๊ฐ€ ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.