์ด ํ์ด์ง์๋ ์ ํ๋ฆฌ์ผ์ด์ ํ ํ๋ฆฟ์ด ์ ๊ณต๋ฉ๋๋ค.
์ด ํ์ด์ง๋ ํ ํ๋ฆฟ์ ๋ผ์ด๋ธ ๋ฐ๋ชจ๋ก ์ฐ๊ฒฐ๋ฉ๋๋ค.
์ด ํ์ด์ง์ ์ํ๋ AI ์ด์์คํดํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฌธ์๋ฅผ ์์ฝํฉ๋๋ค
๋ฒ์ ๊ธฐ๋ก
- "ํ๋ก๋ฐ์ด๋์ ํ
์ react-native-intlayer์์ ์ง์ ๊ฐ์ ธ์ค๊ธฐ; react-intlayer๋ ๋ ์ด์ ์ง์ ์์กด์ฑ์ผ๋ก ํ์ํ์ง ์์"v9.0.02026. 6. 25.
- "Solid useIntlayer API ์ฌ์ฉ๋ฒ์ ์ง์ ์์ฑ ์ก์ธ์ค๋ก ์
๋ฐ์ดํธ"v8.9.02026. 5. 4.
- "init ๋ช
๋ น์ด ์ถ๊ฐ"v7.5.92025. 12. 30.
- "๋๋ฒ๊ทธ ์น์
์ถ๊ฐ"v6.1.62025. 10. 2.
- "์ด๊ธฐ ์ด๋ ฅ"v5.5.102025. 6. 29.
์ด ํ์ด์ง์ ์ฝํ ์ธ ๋ AI๋ฅผ ์ฌ์ฉํ์ฌ ๋ฒ์ญ๋์์ต๋๋ค.
์์ด ์๋ณธ ๋ด์ฉ์ ์ต์ ๋ฒ์ ์ ๋ณด๊ธฐ์ด ๋ฌธ์๋ฅผ ๊ฐ์ ํ ์์ด๋์ด๊ฐ ์์ผ์๋ฉด GitHub์ ํ ๋ฆฌํ์คํธ๋ฅผ ์ ์ถํ์ฌ ์์ ๋กญ๊ฒ ๊ธฐ์ฌํด ์ฃผ์ธ์.
๋ฌธ์์ ๋ํ GitHub ๋งํฌ๋ฌธ์์ Markdown์ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
Expo ๋ฐ React Native ์ฑ ๋ฒ์ญํ๊ธฐ
๋ชฉ์ฐจ
๋์ ๋๋น Intlayer๋ฅผ ์ ํํ๋ ์ด์
react-native-localize๋ i18next์ ๊ฐ์ ์ฃผ์ ์๋ฃจ์
๊ณผ ๋น๊ตํ์ ๋, Intlayer๋ ๋ค์๊ณผ ๊ฐ์ ํตํฉ ์ต์ ํ ๊ธฐ๋ฅ์ ๊ฐ์ถ ์๋ฃจ์
์
๋๋ค:
Intlayer๋ React Native์ Expo์์ ์๋ฒฝํ๊ฒ ์๋ํ๋๋ก ์ต์ ํ๋์ด ์์ผ๋ฉฐ, ์ปดํฌ๋ํธ ์์ค์ ์ฝํ ์ธ ๋ฒ์ ์ง์ , TypeScript ์ง์, ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ฐ์ผ ์ฑ์์ ๊ตญ์ ํ(i18n)๋ฅผ ํ์ฅํ๋ ๋ฐ ํ์ํ ๋ชจ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ ํ๋ฆฌ์ผ์ด์ ์ ์ฝํ ์ธ ๋ฒ์๋ฅผ ์ง์ ํ๋ฉด ๋๊ท๋ชจ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ง ๋ณด์๊ฐ ์ฉ์ดํด์ง๋๋ค. ์ ์ฒด ์ฝํ ์ธ ์ฝ๋๋ฒ ์ด์ค๋ฅผ ๊ฒํ ํด์ผ ํ๋ ๋ถ๋ด ์์ด ๋จ์ผ ๊ธฐ๋ฅ ํด๋๋ฅผ ๋ณต์ ํ๊ฑฐ๋ ์ญ์ ํ ์ ์์ต๋๋ค. ๋ํ Intlayer๋ ์ฝํ ์ธ ์ ์ ํ์ฑ์ ๋ณด์ฅํ๊ธฐ ์ํด ์์ ํ ํ์ ์ด ์ง์ ๋์ด ์์ต๋๋ค.
์ฝํ ์ธ ๋ฅผ ํจ๊ป ๋ฐฐ์นํ๋ฉด ๋ํ ์ธ์ด ๋ชจ๋ธ(LLM)์ ํ์ํ ์ปจํ ์คํธ๊ฐ ์ค์ด๋ญ๋๋ค. Intlayer๋ ๋๋ฝ๋ ๋ฒ์ญ์ ํ ์คํธํ๊ธฐ ์ํ CLI, LSP, MCP, agent skills ๋ฑ์ ๋๊ตฌ ๋ชจ์์ ์ ๊ณตํ์ฌ AI ์์ด์ ํธ๋ฅผ ์ํ ๊ฐ๋ฐ์ ๊ฒฝํ(DX)์ ๋์ฑ ์ํํ๊ฒ ํฉ๋๋ค.
AI ์ ๊ณต์ ์ฒด ๋น์ฉ์ผ๋ก ์ํ๋ LLM์ ์ฌ์ฉํ์ฌ CI/CD ํ์ดํ๋ผ์ธ์์ ์๋ํ๋ก ๋ฒ์ญํ์ธ์. Intlayer๋ ์ฝํ ์ธ ์ถ์ถ์ ์๋ํํ๋ ์ปดํ์ผ๋ฌ์ ๋ฐฑ๊ทธ๋ผ์ด๋์์ ๋ฒ์ญ์ ๋์์ฃผ๋ ์น ํ๋ซํผ๋ ์ ๊ณตํฉ๋๋ค.
๋์ฉ๋ JSON ํ์ผ์ ์ปดํฌ๋ํธ์ ์ฐ๊ฒฐํ๋ฉด ์ฑ๋ฅ ๋ฐ ๋ฐ์์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค. Intlayer๋ ๋น๋ ์ ์ฝํ ์ธ ๋ก๋ฉ์ ์ต์ ํํฉ๋๋ค.
๋จ์ํ i18n ์๋ฃจ์ ์ด์์ผ๋ก, Intlayer๋ ๋ฒ์ญ์ฌ, ์นดํผ๋ผ์ดํฐ, ๊ธฐํ ํ์๋ค๊ณผ์ ํ์ ์ ์ํํ๊ฒ ํ๋ ์์ฒด ํธ์คํ ๋น์ฃผ์ผ ์๋ํฐ์ ์์ ํ CMS๋ฅผ ์ ๊ณตํ์ฌ ๋ค๊ตญ์ด ์ฝํ ์ธ ๋ฅผ ์ค์๊ฐ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฒ ํฉ๋๋ค. ์ฝํ ์ธ ๋ ๋ก์ปฌ ๋ฐ/๋๋ ์๊ฒฉ์ผ๋ก ์ ์ฅํ ์ ์์ต๋๋ค.
ํ์ด์ง์ ๋์ฉ๋ JSON ํ์ผ์ ๋ก๋ํ๋ ๋์ ํ์ํ ์ฝํ ์ธ ๋ง ๋ก๋ํ์ธ์. Intlayer๋ ๋ฒ๋ค ๋ฐ ๋ทฐ ํฌ๊ธฐ๋ฅผ ์ต๋ 50%๊น์ง ์ค์ด๋ ๋ฐ ๋์์ ์ค๋๋ค.
์์กด์ฑ ์ค์น
GitHub์์ ์ ํ๋ฆฌ์ผ์ด์ ํ ํ๋ฆฟ์ ์ฐธ์กฐํ์ธ์.
React Native ํ๋ก์ ํธ์์ ๋ค์ ํจํค์ง๋ค์ ์ค์นํ์ธ์:
bash์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
--interactiveํ๋๊ทธ๋ ์ ํ ์ฌํญ์ ๋๋ค. AI ์์ด์ ํธ์ธ ๊ฒฝ์ฐintlayer-cli init๋ฅผ ์ฌ์ฉํ์ธ์.์ด ๋ช ๋ น์ ํ๊ฒฝ์ ๊ฐ์งํ๊ณ ํ์ํ ํจํค์ง๋ฅผ ์ค์นํฉ๋๋ค. ์๋ฅผ ๋ค์ด:
bash์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
ํจํค์ง
intlayer
๊ตฌ์ฑ, ์ฌ์ ์ฝํ ์ธ , ์ ํ ์์ฑ ๋ฐ CLI ๋ช ๋ น์ ์ํ ํต์ฌ i18n ํดํท์ ๋๋ค.react-native-intlayer
๋ก์ผ์ผ์ ์ป๊ณ ์ ํํ๊ธฐ ์ํด ์ฌ์ฉํ ์ปจํ ์คํธ ํ๋ก๋ฐ์ด๋์ React ํ , React Native ํด๋ฆฌํ, ๊ทธ๋ฆฌ๊ณ Intlayer๋ฅผ React Native ๋ฒ๋ค๋ฌ์ ํตํฉํ๊ธฐ ์ํ Metro ํ๋ฌ๊ทธ์ธ์ ์ ๊ณตํ๋ React Native ํตํฉ์ ๋๋ค.react-intlayer์ ๋ชจ๋ ๊ฒ์ ์ฌ๋ด๋ณด๋ด๋ฏ๋ก React Native ์ฑ์์๋ ์ด ๋จ์ผ ํจํค์ง๋ง ํ์ํฉ๋๋ค.
Intlayer ๊ตฌ์ฑ ์์ฑ
์ํคํ ์ฒ
์ด ์ํคํ ์ฒ์์๋
react-native-intlayer๊ฐ ๋ฃจํธIntlayerProvider์ React Native ํ ์ ์ ๊ณตํ์ฌ ํ๋ฉด๊ณผ ์ปดํฌ๋ํธ ์ ๋ฐ์์ ๋ฒ์ญ์ ๊ด๋ฆฌํฉ๋๋ค. ์ฝํ ์ธ ์ ์ธ์ ํด๋น ์ปดํฌ๋ํธ์ ํจ๊ป ๋ฐฐ์น๋ฉ๋๋ค.bash์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
์ค์
ํ๋ก์ ํธ ๋ฃจํธ(๋๋ ์ ์ ํ ๊ณณ)์ Intlayer ๊ตฌ์ฑ ํ์ผ์ ์์ฑํ์ธ์. ์์:
intlayer.config.ts์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
/** * Locales ํ์ ์ ์ฌ์ฉํ ์ ์๋ ๊ฒฝ์ฐ, tsconfig.json์์ moduleResolution์ "bundler"๋ก ์ค์ ํด ๋ณด์ธ์ */ import { Locales, type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, // ... ํ์ํ ๋ค๋ฅธ ๋ก์ผ์ผ ์ถ๊ฐ ], defaultLocale: Locales.ENGLISH, }, }; export default config;์ด ๊ตฌ์ฑ์์ ๋ค์์ ์ค์ ํ ์ ์์ต๋๋ค:
- ์ง์๋๋ ๋ก์ผ์ผ ๋ชฉ๋ก ๊ตฌ์ฑ.
- ๊ธฐ๋ณธ ๋ก์ผ์ผ ์ค์ .
- ๋์ค์ ๋ ๋ง์ ๊ณ ๊ธ ์ต์ (๋ก๊ทธ, ์ฌ์ฉ์ ์ ์ ์ฝํ ์ธ ๋๋ ํ ๋ฆฌ ๋ฑ)์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ์์ธํ ๋ด์ฉ์ Intlayer ๊ตฌ์ฑ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
Metro ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
Metro๋ React Native์ ๋ฒ๋ค๋ฌ์ ๋๋ค.
react-native init๋ช ๋ น์ผ๋ก ์์ฑ๋ React Native ํ๋ก์ ํธ์ ๊ธฐ๋ณธ ๋ฒ๋ค๋ฌ์ ๋๋ค. Intlayer๋ฅผ Metro์ ํจ๊ป ์ฌ์ฉํ๋ ค๋ฉดmetro.config.jsํ์ผ์ ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐํด์ผ ํฉ๋๋ค:metro.config.js์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
์ฐธ๊ณ :
configMetroIntlayer๋ Promise ํจ์์ ๋๋ค. ๋๊ธฐ์ ์ผ๋ก ์ฌ์ฉํ๊ฑฐ๋ IIFE(์ฆ์ ํธ์ถ ํจ์ ํํ์)๋ฅผ ํผํ๋ ค๋ฉดconfigMetroIntlayerSync๋ฅผ ์ฌ์ฉํ์ธ์. ์ฐธ๊ณ :configMetroIntlayerSync๋ ์๋ฒ ์์ ์ intlayer ์ฌ์ ๋น๋๋ฅผ ํ์ฉํ์ง ์์ต๋๋ค.Intlayer ํ๋ก๋ฐ์ด๋ ์ถ๊ฐ
์ ํ๋ฆฌ์ผ์ด์ ์ ์ฒด์์ ์ฌ์ฉ์ ์ธ์ด๋ฅผ ๋๊ธฐํํ๋ ค๋ฉด ๋ฃจํธ ์ปดํฌ๋ํธ๋ฅผ
react-native-intlayer์IntlayerProvider์ปดํฌ๋ํธ๋ก ๊ฐ์ธ์ผ ํฉ๋๋ค.ํญ์
react-native-intlayer์์ ๊ฐ์ ธ์ค์ธ์. ์ด ํจํค์ง์IntlayerProvider๋ Intlayer๊ฐ ์ฌ์ฉํ๋ ์น API์ ๋ํ ํด๋ฆฌํ์ ํฌํจํ๋ฉฐ,react-intlayer์ ๋ชจ๋ ํ ๊ณผ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ๋ด๋ณด๋ ๋๋ค.๋ํ Intlayer๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ์๋ํ ์ ์๋๋ก
index.jsํ์ผ์intlayerPolyfillํจ์๋ฅผ ์ถ๊ฐํด์ผ ํฉ๋๋ค.app/_layout.tsx์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
import { Stack } from "expo-router"; import { getLocales } from "expo-localization"; import { IntlayerProvider } from "react-native-intlayer"; import { type FC } from "react"; const getDeviceLocale = () => getLocales()[0]?.languageTag; const RootLayout: FC = () => { return ( <IntlayerProvider defaultLocale={getDeviceLocale()}> <Stack> <Stack.Screen name="(tabs)" options={{ headerShown: false }} /> </Stack> </IntlayerProvider> ); }; export default RootLayout;์ฝํ ์ธ ์ ์ธํ๊ธฐ
ํ๋ก์ ํธ ๋ด ์ด๋์์๋(์ผ๋ฐ์ ์ผ๋ก
src/๋ด) ์ฝํ ์ธ ์ ์ธ ํ์ผ์ ์์ฑํ์ธ์. Intlayer๊ฐ ์ง์ํ๋ ํ์ฅ์ ํ์์ ์ฌ์ฉํ ์ ์์ต๋๋ค:.content.json.content.jsonc.content.json5.content.ts.content.tsx.content.js.content.jsx.content.mjs.content.mjx.content.cjs.content.md.content.mdx.content.yaml.content.yml- ๊ธฐํ
Expo Router (์น):
.content.*ํ์ผ์app/๋๋ ํ ๋ฆฌ ์ธ๋ถ์ ๋ณด๊ดํ์ธ์. Expo Router๋app/๋ด์ ๋ชจ๋ JavaScript/TypeScript ํ์ผ์ ๋ผ์ฐํธ๋ก ์ทจ๊ธํฉ๋๋ค. ์น์์๋ ๋ผ์ฐํธ ๊ฒ์์ด ํ์ผ ์์คํ ์ ์ง์ ์ค์บํ๋ฉฐ Metro์resolver.blockList๋ฅผ ๋ฐ๋ฅด์ง ์์ผ๋ฏ๋ก, ํจ๊ป ์์นํ*.content.ts๊ฐ ๋ผ์ฐํธ๋ก ๋ฑ๋ก๋ฉ๋๋ค.app/(tabs)/_layout.content.ts์ ๊ฐ์ ํ์ผ์ ๋ ์ด์์์ผ๋ก ํ์ฑ๋๊ธฐ๋ ํ๋ฉฐ(.content๋ถ๋ถ์ด ํ๋ซํผ ์ ๋ฏธ์ฌ๋ก ์ฝํ), ์ด๋ ์ค์ _layout.tsx์ ์ถฉ๋ํ์ฌ ๋ค์ ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค:plaintext์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
์ ์ธ์
app/์ธ๋ถ์ ๋๋ ํ ๋ฆฌ(์:content/๋๋src/content/)์ ๋ฐฐ์นํ์ธ์. Intlayer๋ ํ๋ก์ ํธ ์ด๋์์๋.content.*ํ์ผ์ ๋ฐ๊ฒฌํ๋ฉฐ ๋์ ๋๋ฆฌ๋ ํด๋นkey๋ก ์ฐธ์กฐ๋๋ฏ๋ก ๊ฐ์ ธ์ค๊ธฐ(import)๋ฅผ ๋ณ๊ฒฝํ ํ์๊ฐ ์์ต๋๋ค. ๋ค์ดํฐ๋ธ์์๋ ์ด๊ฒ์ด ํ์ํ์ง ์์ง๋ง(Metro์blockList๊ฐ ์ด๋ฏธ ์จ๊น ์ฒ๋ฆฌํจ),app/์ธ๋ถ ๋๋ ํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ํ๋ซํผ ๋ชจ๋ ์ ์์ ์ผ๋ก ์๋ํฉ๋๋ค.์์ (React Native์ฉ TSX ๋ ธ๋๋ฅผ ํฌํจํ TypeScript):
src/app.content.tsx์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
import { t, type Dictionary } from "intlayer"; import type { ReactNode } from "react"; /** * "app" ๋๋ฉ์ธ์ฉ ์ฝํ ์ธ ์ฌ์ */ import { t, type Dictionary } from "intlayer"; const homeScreenContent = { key: "home-screen", content: { title: t({ en: "Welcome!", fr: "Bienvenue!", es: "ยกBienvenido!", }), }, } satisfies Dictionary; export default homeScreenContent;์ฝํ ์ธ ์ ์ธ์ ๋ํ ์์ธํ ๋ด์ฉ์ Intlayer ์ฝํ ์ธ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
์ปดํฌ๋ํธ์์ Intlayer ์ฌ์ฉํ๊ธฐ
์์ ์ปดํฌ๋ํธ์์
useIntlayerํ ์ ์ฌ์ฉํ์ฌ ์ง์ญํ๋ ์ฝํ ์ธ ๋ฅผ ๊ฐ์ ธ์ค์ธ์.์์
app/(tabs)/index.tsx์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
import { Image, StyleSheet, Platform } from "react-native"; import { useIntlayer } from "react-native-intlayer"; import { HelloWave } from "@/components/HelloWave"; import ParallaxScrollView from "@/components/ParallaxScrollView"; import { ThemedText } from "@/components/ThemedText"; import { ThemedView } from "@/components/ThemedView"; import { type FC } from "react"; const HomeScreen = (): FC => { const { title, steps } = useIntlayer("home-screen"); return ( <ParallaxScrollView headerBackgroundColor={{ light: "#A1CEDC", dark: "#1D3D47" }} headerImage={ <Image source={require("@/assets/images/partial-react-logo.png")} style={styles.reactLogo} /> } > <ThemedView style={styles.titleContainer}> <ThemedText type="title">{title}</ThemedText> <HelloWave /> </ThemedView> </ParallaxScrollView> ); }; const styles = StyleSheet.create({ titleContainer: { flexDirection: "row", alignItems: "center", gap: 8, }, }); export default HomeScreen;๋ฌธ์์ด ๊ธฐ๋ฐ prop(์: ๋ฒํผ์
title๋๋Text์ปดํฌ๋ํธ์children)์์content.someKey๋ฅผ ์ฌ์ฉํ ๋๋ ์ค์ ๋ฌธ์์ด์ ์ป๊ธฐ ์ํดcontent.someKey.value๋ฅผ ํธ์ถํ์ธ์.์ฑ์ด ์ด๋ฏธ ์กด์ฌํ๋ค๋ฉด Intlayer Compiler์ extract ๋ช ๋ น์ด๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒ ๊ฐ์ ์ปดํฌ๋ํธ๋ฅผ ํ ๋ฒ์ ๋ณํํ ์ ์์ต๋๋ค.
์ฑ ๋ก์ผ์ผ ๋ณ๊ฒฝํ๊ธฐ
์ ํ์ฌํญ์ปดํฌ๋ํธ ๋ด์์ ๋ก์ผ์ผ์ ์ ํํ๋ ค๋ฉด
useLocaleํ ์setLocale๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:src/components/LocaleSwitcher.tsx์ฝ๋ ๋ณต์ฌ์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
import { type FC } from "react"; import { View, Text, TouchableOpacity, StyleSheet } from "react-native"; import { getLocaleName } from "intlayer"; import { useLocale } from "react-native-intlayer"; export const LocaleSwitcher: FC = () => { const { setLocale, availableLocales } = useLocale(); return ( <View style={styles.container}> {availableLocales.map((locale) => ( <TouchableOpacity key={locale} style={styles.button} onPress={() => setLocale(locale)} > <Text style={styles.text}>{getLocaleName(locale)}</Text> </TouchableOpacity> ))} </View> ); }; const styles = StyleSheet.create({ container: { flexDirection: "row", justifyContent: "center", alignItems: "center", gap: 8, }, button: { paddingVertical: 6, paddingHorizontal: 12, borderRadius: 6, backgroundColor: "#ddd", }, text: { fontSize: 14, fontWeight: "500", color: "#333", }, });์ด ์ฝ๋๋ Intlayer ์ฝํ ์ธ ๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ์ปดํฌ๋ํธ์ ๋ฆฌ๋ ๋๋ง์ ํธ๋ฆฌ๊ฑฐํ๋ฉฐ, ์ด์ ์๋ก์ด ๋ก์ผ์ผ์ ๋ํ ๋ฒ์ญ์ ํ์ํฉ๋๋ค.
์์ธํ ๋ด์ฉ์
useLocale๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
TypeScript ๊ตฌ์ฑํ๊ธฐ (TypeScript๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ)
Intlayer๋ ์๋ ์์ฑ ๊ธฐ๋ฅ์ ํฅ์์ํค๊ณ ๋ฒ์ญ ์ค๋ฅ๋ฅผ ์ก๊ธฐ ์ํด ์จ๊ฒจ์ง ํด๋(๊ธฐ๋ณธ๊ฐ์ .intlayer)์ ํ์
์ ์๋ฅผ ์์ฑํฉ๋๋ค:
์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
์ด ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค:
- ์ฌ์ ํค์ ๋ํ ์๋ ์์ฑ.
- ์กด์ฌํ์ง ์๋ ํค์ ์ ๊ทผํ๊ฑฐ๋ ํ์ ์ด ์ผ์นํ์ง ์์ ๋ ๊ฒฝ๊ณ ํ๋ ํ์ ๊ฒ์ฌ.
Git ์ค์
Intlayer๊ฐ ์๋ ์์ฑํ ํ์ผ์ ์ปค๋ฐํ์ง ์๋๋ก ํ๋ ค๋ฉด, .gitignore์ ๋ค์์ ์ถ๊ฐํ์ธ์:
์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
VS Code ํ์ฅ
Intlayer์ ํจ๊ป ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๊ธฐ ์ํด ๊ณต์ Intlayer VS Code ํ์ฅ์ ์ค์นํ ์ ์์ต๋๋ค.
์ด ํ์ฅ ๊ธฐ๋ฅ์ ๋ค์์ ์ ๊ณตํฉ๋๋ค:
- ๋ฒ์ญ ํค์ ๋ํ ์๋ ์์ฑ.
- ๋๋ฝ๋ ๋ฒ์ญ์ ๋ํ ์ค์๊ฐ ์ค๋ฅ ๊ฐ์ง.
- ๋ฒ์ญ๋ ์ฝํ ์ธ ์ ์ธ๋ผ์ธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ.
- ๋ฒ์ญ์ ์ฝ๊ฒ ์์ฑํ๊ณ ์ ๋ฐ์ดํธํ ์ ์๋ ๋น ๋ฅธ ์์ .
ํ์ฅ ๊ธฐ๋ฅ ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํ ์์ธํ ๋ด์ฉ์ Intlayer VS Code ํ์ฅ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ ๋์๊ฐ๊ธฐ
Intlayer๋ฅผ ํตํด ์๋ฒฝํ๊ฒ ์ง์๋๋ i18n์ผ๋ก React Native ์ฑ์ ์ฆ๊ฒ๊ฒ ๊ฐ๋ฐํ์ธ์!
Debug
Intlayer๋ ์ฃผ๋ก Web Intl API๋ฅผ ๋์์ผ๋ก ํ๋ฉฐ, React Native์์๋ ์ ์ ํ ํด๋ฆฌํ์ ํฌํจํด์ผ ํฉ๋๋ค.
Intlayer๋ ์ฃผ๋ก Web Intl API๋ฅผ ๋์์ผ๋ก ํฉ๋๋ค. React Native์์๋ ์ ์ ํ polyfills์ ํฌํจํด์ผ ํฉ๋๋ค.
์ฒดํฌ๋ฆฌ์คํธ:
intlayer์react-native-intlayer์ ์ต์ ๋ฒ์ ์ ์ฌ์ฉํ์ธ์.- Intlayer ํด๋ฆฌํ์ ํ์ฑํํ์ธ์.
getLocaleName๋๋ ๋ค๋ฅธ Intl-API ๊ธฐ๋ฐ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, ์ด๋ฌํ ํด๋ฆฌํ์ ๋จผ์ importํ์ธ์ (์:index.js๋๋App.tsx):
์ฝ๋๋ฅผ ํด๋ฆฝ๋ณด๋์ ๋ณต์ฌ
- ๋ชจ๋์ ํ์ธํ ์ ์์ผ๋ฉด Metro ๊ตฌ์ฑ(resolver aliases, asset plugins,
tsconfigpaths)์ ํ์ธํ์ธ์.
์์ฃผ ๋ฌป๋ ์ง๋ฌธ
i18n-js(expo-localization๊ณผ ํจ๊ป ์ฌ์ฉ): ๊ฐ์ฅ ์ ํต์ ์ธ ์กฐํฉ์ผ๋ก, ํ์ ์์ ์ฑ์ด ์๋ ์ผ๋ฐ ๋ฉ์์ง ๊ฐ์ฒด์ ๋๋ค.react-i18next: React ์ํ๊ณ์ ํ์ค์ผ๋ก, ๋ฐํ์์ JSON ๋ค์์คํ์ด์ค๋ฅผ ๋ก๋ํฉ๋๋ค.Intlayer: ๊ฐ์ฅ ์ง๋ณด๋ ์๋ฃจ์ ์ ๋๋ค. ์ฝ๋๋ฒ ์ด์ค ์ด๋์๋ ์ฝํ ์ธ ๋ฅผ ์ ์ธํ ์ ์์ผ๋ฉฐ(๊ฐ ์ปดํฌ๋ํธ ์ ๋๋ ์ค์ ์ง์ค์), Metro ํ๋ฌ๊ทธ์ธ์ ์ํด ๋น๋ ํ์์ ์ปดํ์ผ๋๊ณ , ์์ ํ ํ์ ์์ ์ฑ์ ์ ๊ณตํ๋ฉฐ AI ๋ฒ์ญ, ๋น์ฃผ์ผ ์๋ํฐ ๋ฐ CMS๋ฅผ ์ง์ํฉ๋๋ค.
๋ชจ๋ฐ์ผ์์๋ ํ์ด์ง๋ณ๋ก ๊ฐ์ ธ์ค๋ ์น๊ณผ ๋ฌ๋ฆฌ ๋ชจ๋ ๊ฒ์ด ์ฑ ๋ฒ๋ค์ ํฌํจ๋๊ธฐ ๋๋ฌธ์ ๋ฒ๋ค ํฌ๊ธฐ ์ ๊ฐ ํจ๊ณผ๊ฐ ํจ์ฌ ๊ฐ๋ ฅํฉ๋๋ค. ์ปดํฌ๋ํธ๋ณ๋ก ์ฝํ ์ธ ๋ฅผ ์ปดํ์ผํ๋ฉด ์ฌ์ฉ๋์ง ์๋ ์ธ์ด์ ํค๊ฐ ๋ฒ๋ค์์ ์์ ํ ์ ์ธ๋ฉ๋๋ค. ์ Intlayer์ธ๊ฐ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ฐํ์ ์นดํ๋ก๊ทธ๋ณด๋ค ํจ์ฌ ์ ์ต๋๋ค. ๋ชจ๋ฐ์ผ์์๋ ํ์ด์ง๋ณ๋ก ๊ฐ์ ธ์ค๋ ์น๊ณผ ๋ฌ๋ฆฌ ๋ชจ๋ ๋ฆฌ์์ค๊ฐ ์ฑ ๋ด์ ๋ฒ๋ค๋ง๋๋ฏ๋ก ์ด๊ฒ์ด ๋์ฑ ์ค์ํฉ๋๋ค. Metro ํ๋ฌ๊ทธ์ธ์ useIntlayer ํธ์ถ์ ์ปดํฌ๋ํธ๊ฐ ์ฌ์ฉํ๋ ์ ํํ ํญ๋ชฉ์ผ๋ก ํ์ธํ๋ฏ๋ก ์ฌ์ฉ๋์ง ์๋ ํค์ ์ธ์ด๋ ๋ฐ์ด๋๋ฆฌ์ ์ ๋ ํฌํจ๋์ง ์์ต๋๋ค. ์ผ๋ฐ์ ์ธ ๋์๋ค๊ณผ ๋น๊ตํ์ ๋ Intlayer๋ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ต๋ 50%๊น์ง ์ค์ฌ์ค๋๋ค. ๋ฒ๋ค ์ต์ ํ๋ฅผ ์ฐธ์กฐํ์ธ์.
๋ค, ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. i18n-js ๋ง์ด๊ทธ๋ ์ด์
๊ฐ์ด๋ ๋๋ react-i18next ๋ง์ด๊ทธ๋ ์ด์
๊ฐ์ด๋๋ฅผ ๋ฐ๋ผ ์ ์ง์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ ์ ์์ต๋๋ค. ๋๋ ํ์ฌ API๋ฅผ ์์ ํ ์ ์งํ ์๋ ์์ต๋๋ค. ํธํ ์ด๋ํฐ(compat adapters)๋ react-i18next ๋ฐ react-intl๊ณผ ์์ ํ ๋์ผํ API๋ฅผ ๋
ธ์ถํ๋ฉด์ Intlayer ์ฌ์ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ณตํ๋ฏ๋ก, import ๊ตฌ๋ฌธ๋ง ๋ณ๊ฒฝํ๊ณ ์ปดํฌ๋ํธ ์ฝ๋๋ ๊ทธ๋๋ก ์ ์งํ ์ ์์ต๋๋ค.
๋ค. sync JSON ํ๋ฌ๊ทธ์ธ์ /messages/{locale}/{namespace}.json ํ์ผ์ ๋จ์ผ ์ง์ค ๊ณต๊ธ์(source of truth)์ผ๋ก ์ ์งํ๋ฉด์ ์๋ฐฉํฅ์ผ๋ก Intlayer ์ฌ์ ์ ์์ฑํฉ๋๋ค. sync PO ํ๋ฌ๊ทธ์ธ์ gettext ์นดํ๋ก๊ทธ์ ๋ํด ๋์ผํ ์์
์ ์ํํ๋ฉฐ, ๋ก์ผ์ผ๋ณ ํ์ผ์ ํตํด ๋ก์ผ์ผ์ ํ ํ์ผ์ ๋ชจ์ผ๋ ๋์ ์ธ์ด๋ณ๋ก ์ฝํ
์ธ ๋ฅผ ๋ถํ ํ ์๋ ์์ต๋๋ค.
์๋๋๋ค. npx intlayer extract๋ฅผ ์คํํ๋ฉด Intlayer๊ฐ ์์ค ํ์ผ์ ์ฝ๊ณ ์ฌ์ฉ์ ๋๋ฉด ๋ฌธ์์ด์ ์ถ์ถํ์ฌ ๊ฐ ์ปดํฌ๋ํธ ์์ .content ํ์ผ์ ์์ฑํ๋ฏ๋ก ์นดํ๋ก๊ทธ์ ์ผ์ผ์ด ๋ณต์ฌํ ํ์ ์์ด diff๋ง ๊ฒํ ํ๋ฉด ๋ฉ๋๋ค. extract ๋ช
๋ น์ ์ฐธ์กฐํ์ธ์.
์์ ์๋ํ๋ ํ์ดํ๋ผ์ธ์ ์ํด Intlayer ์ปดํ์ผ๋ฌ๋ ๋น๋ ํ์์ JSX, TSX, Vue ๋ฐ Svelte ์์ค์์ ๋์ผํ ์์ ์ ์ํํ์ฌ ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์ฌ์ ์ ์์ฑํ๊ณ HMR์ ํตํด ๋๊ธฐํํ๋ฏ๋ก ์๋์ผ๋ก ํค๋ฅผ ๊ด๋ฆฌํ ํ์๊ฐ ์์ต๋๋ค. ์ ์ ๋ถ์์ผ๋ก ์๋ํ๋ฏ๋ก ๋ฐํ์์๋ง ์กด์ฌํ๋ ๋ฌธ์์ด์ ์ ์ธ๋๋ฉฐ, ์ฌ์ฉ์ ํ ์คํธ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง์ ๊ตฌ๋ถํ๊ธฐ ์ํด ๋ช ๊ฐ์ง ์ฃผ์์ด ํ์ํฉ๋๋ค.
5๊ฐ์ง ๋๊ตฌ๊ฐ ๋ชจ๋ ์ ํ ์ฌํญ์ผ๋ก ์ ๊ณต๋ฉ๋๋ค:
- VS Code ํ์ฅ ํ๋ก๊ทธ๋จ:
useIntlayerํค์์ ์ด๋ฅผ ์ ์ธํ ์ฝํ ์ธ ํ์ผ๋ก ๋ฐ๋ก ์ด๋ํ๊ณ , ์ปดํฌ๋ํธ์์ ์ฝํ ์ธ ๋ฅผ ์ถ์ถํ๋ฉฐ, ๋ช ๋ น ํ๋ ํธ๋ ์ ์ฉ Intlayer ํญ์์ build, fill, test, push, pull์ ์คํํ ์ ์์ต๋๋ค. - LSP ์๋ฒ: LSP๋ฅผ ์ง์ํ๋ ๋ชจ๋ ์๋ํฐ์์ ์ ์๋ก ์ด๋, ๋ชจ๋ ์ฐธ์กฐ ์ฐพ๊ธฐ, ๋ฒ์ญ ๊ฐ ๋ง์ฐ์ค ์ค๋ฒ ๋ฏธ๋ฆฌ๋ณด๊ธฐ, ํค ๋ฐ ํ๋ ์๋ ์์ฑ, ์ ์ธ๋์ง ์์ ํค์ ๋ํ ๊ฒฝ๊ณ ๋ฑ ๋์ผํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ํ
i18next,react-i18next,next-intl,use-intlํธ์ถ๋ ํด์ํ๋ฏ๋ก ๋ง์ด๊ทธ๋ ์ด์ ์ ์ ์ฉํฉ๋๋ค. - MCP ์๋ฒ: Cursor, VS Code, Claude Desktop, Claude Code, ChatGPT์ Intlayer ๋ฌธ์์ CLI๋ฅผ ๋
ธ์ถํ์ฌ AI ์ด์์คํดํธ๊ฐ ์ต์ ๋ฌธ์๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ํํ ๋ต๋ณํ๊ณ
intlayer fill๋ฑ์ ๋ช ๋ น์ ์ง์ ์คํํ ์ ์๊ฒ ํฉ๋๋ค. - Agent Skills:
intlayer-config,intlayer-cli,intlayer-content๋ฐ ๊ฐ ํ๋ ์์ํฌ ์ ์ฉ ์คํฌ์ ํตํด AI ์์ด์ ํธ์๊ฒ ๋ผ์ฐํ ์ค์ ๊ณผ ์ฝํ ์ธ ๋ ธ๋ ํ์ ์ ํ์ต์ํต๋๋ค. - ESLint ํ๋ฌ๊ทธ์ธ:
no-raw-text๊ท์น์ผ๋ก ํ๋์ฝ๋ฉ๋ ๋ฌธ์์ด์ ํ์ํ๊ณ , ์ ์ ์ฌ์ ํค ๋ฐ ์ฌ์ฉ๋์ง ์๋ ์ฝํ ์ธ ์ ๋ํ ์ถ๊ฐ ๊ท์น์ ์ ๊ณตํฉ๋๋ค.
